From 413b183ea18e0f84fc05d68606880f9e8e28e849 Mon Sep 17 00:00:00 2001 From: Patrik Date: Thu, 21 Mar 2024 15:10:48 +0100 Subject: [PATCH] refactor: Use `typed-builder` instead of custom one for `VerificationMethod` (#1162) --- Cargo.lock | 1 + .../did_exchange/state_machine/helpers.rs | 17 +- did_core/did_doc/src/schema/did_doc.rs | 89 +++--- did_core/did_doc/src/schema/legacy.rs | 299 ------------------ did_core/did_doc/src/schema/mod.rs | 1 - .../src/schema/verification_method/mod.rs | 208 +----------- did_core/did_methods/did_peer/Cargo.toml | 1 + .../did_methods/did_peer/examples/demo.rs | 17 +- .../peer_did/numalgos/numalgo2/encoding.rs | 19 +- .../numalgos/numalgo2/verification_method.rs | 104 +++--- .../numalgos/numalgo4/encoded_document.rs | 25 +- .../src/peer_did/numalgos/numalgo4/mod.rs | 13 +- .../src/dereferencing/utils.rs | 24 +- .../did_resolver_sov/src/resolution/utils.rs | 17 +- did_core/did_parser_nom/src/did_url/mod.rs | 1 + 15 files changed, 179 insertions(+), 657 deletions(-) delete mode 100644 did_core/did_doc/src/schema/legacy.rs diff --git a/Cargo.lock b/Cargo.lock index 5020cd71c5..c41442a9bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1851,6 +1851,7 @@ dependencies = [ "sha256", "thiserror", "tokio", + "typed-builder 0.16.2", "unsigned-varint", "url", ] diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index fe35f59295..e1945c186b 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -7,7 +7,7 @@ use did_doc::schema::{ did_doc::DidDocument, service::{service_key_kind::ServiceKeyKind, typed::didcommv1::ServiceDidCommV1, Service}, types::uri::Uri, - verification_method::{VerificationMethod, VerificationMethodType}, + verification_method::{PublicKeyField, VerificationMethod, VerificationMethodType}, }; use did_key::DidKey; use did_parser_nom::{Did, DidUrl}; @@ -99,13 +99,14 @@ fn did_doc_from_keys( service: Service, ) -> Result { let vm_ka_id = DidUrl::from_fragment(key_enc.short_prefixless_fingerprint())?; - let vm_ka = VerificationMethod::builder( - vm_ka_id, - did.clone(), - VerificationMethodType::Ed25519VerificationKey2020, - ) - .add_public_key_base58(key_enc.base58()) - .build(); + let vm_ka = VerificationMethod::builder() + .id(vm_ka_id) + .controller(did.clone()) + .verification_method_type(VerificationMethodType::Ed25519VerificationKey2020) + .public_key(PublicKeyField::Base58 { + public_key_base58: key_enc.base58(), + }) + .build(); Ok(DidDocument::builder(did) .add_service(service) .add_key_agreement(vm_ka) diff --git a/did_core/did_doc/src/schema/did_doc.rs b/did_core/did_doc/src/schema/did_doc.rs index 52e89843e4..087de03109 100644 --- a/did_core/did_doc/src/schema/did_doc.rs +++ b/did_core/did_doc/src/schema/did_doc.rs @@ -280,21 +280,24 @@ mod tests { let controller = Did::parse("did:example:controller".to_string()).unwrap(); let vm1_id = DidUrl::parse("did:example:vm1#vm1".to_string()).unwrap(); - let verification_method = VerificationMethod::builder( - vm1_id.clone(), - Did::parse("did:example:vm1".to_string()).unwrap(), - VerificationMethodType::Ed25519VerificationKey2018, - ) - .add_public_key_base58("H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV".to_string()) - .build(); + let verification_method = VerificationMethod::builder() + .id(vm1_id.clone()) + .controller(Did::parse("did:example:vm1".to_string()).unwrap()) + .verification_method_type(VerificationMethodType::Ed25519VerificationKey2018) + .public_key(PublicKeyField::Base58 { + public_key_base58: "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV".to_string(), + }) + .build(); + let authentication_reference = DidUrl::parse("did:example:authref".to_string()).unwrap(); - let assertion_method = VerificationMethod::builder( - DidUrl::parse("did:example:am1".to_string()).unwrap(), - Did::parse("did:example:am2".to_string()).unwrap(), - VerificationMethodType::Ed25519VerificationKey2018, - ) - .add_public_key_base58("H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV".to_string()) - .build(); + let assertion_method = VerificationMethod::builder() + .id(DidUrl::parse("did:example:am1".to_string()).unwrap()) + .controller(Did::parse("did:example:am2".to_string()).unwrap()) + .verification_method_type(VerificationMethodType::Ed25519VerificationKey2018) + .public_key(PublicKeyField::Base58 { + public_key_base58: "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV".to_string(), + }) + .build(); let service_id = Uri::new("did:example:123456789abcdefghi;service-1").unwrap(); let service_endpoint = "https://example.com/service"; @@ -473,39 +476,34 @@ mod tests { .unwrap(); let vm1_id = DidUrl::parse("#g1".to_string()).unwrap(); - let vm1 = VerificationMethod::builder( - vm1_id, - controller.clone(), - VerificationMethodType::JsonWebKey2020, - ) - .add_public_key_jwk( - JsonWebKey::from_str( - r#"{ + let vm1 = VerificationMethod::builder() + .id(vm1_id) + .controller(controller.clone()) + .verification_method_type(VerificationMethodType::JsonWebKey2020) + .public_key(PublicKeyField::Jwk { + public_key_jwk: JsonWebKey::from_str( + r#"{ "kty": "EC", "crv": "BLS12381_G1", "x": "hxF12gtsn9ju4-kJq2-nUjZQKVVWpcBAYX5VHnUZMDilClZsGuOaDjlXS8pFE1GG" - }"#, - ) - .unwrap(), - ) - .build(); + }"#, + ) + .unwrap(), + }) + .build(); let vm2_id = DidUrl::parse("#g2".to_string()).unwrap(); - let vm2 = VerificationMethod::builder( - vm2_id, - controller.clone(), - VerificationMethodType::JsonWebKey2020, - ) - .add_public_key_jwk( - JsonWebKey::from_str( - r#"{ + let vm2 = VerificationMethod::builder() + .id(vm2_id) + .controller(controller.clone()) + .verification_method_type(VerificationMethodType::JsonWebKey2020) + .public_key(PublicKeyField::Jwk { public_key_jwk: JsonWebKey::from_str( + r#"{ "kty": "EC", "crv": "BLS12381_G2", "x": "l4MeBsn_OGa2OEDtHeHdq0TBC8sYh6QwoI7QsNtZk9oAru1OnGClaAPlMbvvs73EABDB6GjjzybbOHarkBmP6pon8H1VuMna0nkEYihZi8OodgdbwReDiDvWzZuXXMl-" }"#, - ) - .unwrap(), - ) + ).unwrap()}) .build(); assert_eq!(did_doc.verification_method().first().unwrap().clone(), vm1); @@ -550,13 +548,14 @@ mod tests { "did:web:did-actor-alice#zC8GybikEfyNaausDA4mkT4egP7SNLx2T1d1kujLQbcP6h".to_string(), ) .unwrap(); - let ka1 = VerificationMethod::builder( - ka1_id, - controller, - VerificationMethodType::X25519KeyAgreementKey2019, - ) - .add_public_key_base58("CaSHXEvLKS6SfN9aBfkVGBpp15jSnaHazqHgLHp8KZ3Y".to_string()) - .build(); + let ka1 = VerificationMethod::builder() + .id(ka1_id) + .controller(controller.clone()) + .verification_method_type(VerificationMethodType::X25519KeyAgreementKey2019) + .public_key(PublicKeyField::Base58 { + public_key_base58: "CaSHXEvLKS6SfN9aBfkVGBpp15jSnaHazqHgLHp8KZ3Y".to_string(), + }) + .build(); assert_eq!( did_doc.key_agreement(), diff --git a/did_core/did_doc/src/schema/legacy.rs b/did_core/did_doc/src/schema/legacy.rs deleted file mode 100644 index d335e5319e..0000000000 --- a/did_core/did_doc/src/schema/legacy.rs +++ /dev/null @@ -1,299 +0,0 @@ -use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine}; -use did_parser_nom::{Did, DidUrl}; -use public_key::{Key, KeyType}; -use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; - -use crate::schema::{ - did_doc::DidDocument, - service::Service, - verification_method::{VerificationMethod, VerificationMethodType}, -}; - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, display_as_json::Display)] -#[serde(deny_unknown_fields)] -pub struct LegacyDidDoc { - id: Did, - #[serde(default)] - #[serde(rename = "publicKey")] - public_key: Vec, - #[serde(default)] - authentication: Vec, - service: Vec, -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, display_as_json::Display)] -pub struct LegacyKeyAgreement { - id: String, - #[serde(rename = "type")] - verification_method_type: String, - controller: String, - #[serde(rename = "publicKeyBase58")] - public_key_base_58: String, -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, display_as_json::Display)] -pub struct LegacyAuthentication { - #[serde(rename = "type")] - verification_method_type: String, - #[serde(rename = "publicKey")] - public_key: String, -} - -fn resolve_legacy_authentication_key( - legacy_authentication: &LegacyAuthentication, - legacy_public_keys: &[LegacyKeyAgreement], -) -> Result { - if let Some(fragment) = legacy_authentication.public_key.split('#').last() { - Ok(legacy_public_keys - .iter() - .find(|pk| pk.id.ends_with(fragment)) - .ok_or_else(|| format!("Public key with id {} not found", fragment))? - .public_key_base_58 - .clone()) - } else { - Ok(legacy_authentication.public_key.clone()) - } -} - -fn collect_authentication_fingerprints(legacy_ddo: &LegacyDidDoc) -> Result, String> { - let mut authentication_fingerprints = vec![]; - - for auth in &legacy_ddo.authentication { - let resolved_legacy_authentication_key = match auth.verification_method_type.as_str() { - "Ed25519SignatureAuthentication2018" => { - resolve_legacy_authentication_key(auth, &legacy_ddo.public_key)? - } - "Ed25519Signature2018" => auth.public_key.clone(), - _ => { - continue; - } - }; - - let fingerprint = Key::from_base58(&resolved_legacy_authentication_key, KeyType::Ed25519) - .map_err(|err| { - format!( - "Error converting legacy authentication key to new key: {:?}, error: {:?}", - auth, err - ) - })? - .fingerprint(); - - authentication_fingerprints.push(fingerprint); - } - - for vm in &legacy_ddo.public_key { - // Ed25519VerificationKey2018 check is used due to aries-vcx using this as key type in - // the legacy did doc - if !&["Ed25519Signature2018", "Ed25519VerificationKey2018"] - .contains(&vm.verification_method_type.as_str()) - { - continue; - } - - let fingerprint = Key::from_base58(vm.public_key_base_58.as_str(), KeyType::Ed25519) - .map_err(|err| { - format!( - "Error converting legacy public key to new key: {:?}, error: {:?}", - vm, err - ) - })? - .fingerprint(); - - if !authentication_fingerprints.contains(&fingerprint) { - authentication_fingerprints.push(fingerprint); - } - } - - Ok(authentication_fingerprints) -} - -fn collect_encoded_services(legacy_ddo: &LegacyDidDoc) -> Vec { - let mut encoded_services = vec![]; - for service in &legacy_ddo.service { - let priority = service.extra_field_priority().unwrap_or(0); - let routing_keys = service.extra_field_routing_keys().unwrap_or(vec![]); - let recipient_keys = service.extra_field_recipient_keys().unwrap_or(vec![]); - let service_endpoint = service.service_endpoint().to_string(); - let service_type = service.service_types().first().unwrap().to_string(); - let service = json!({ - "priority": priority, - "r": routing_keys, - "recipientKeys": recipient_keys, - "s": service_endpoint, - "t": service_type, - }); - let service_encoded = STANDARD_NO_PAD.encode(service.to_string().as_bytes()); - encoded_services.push(service_encoded); - } - encoded_services -} - -fn construct_peer_did( - authentication_fingerprints: &[String], - encoded_services: &[String], -) -> Result { - // TODO: Perhaps proper ID is did:peer:3 with alsoKnowAs set to did:peer:2 (or vice versa?) - let mut did = "did:peer:2".to_string(); - - for fingerprint in authentication_fingerprints { - did.push_str(&format!(".V{}", fingerprint)); - } - - for service in encoded_services { - did.push_str(&format!(".S{}", service)); - } - - Did::parse(did).map_err(|err| format!("Error parsing peer did, error: {:?}", err)) -} - -fn construct_new_did_document( - legacy_ddo: &LegacyDidDoc, - authentication_fingerprints: &[String], - did: Did, -) -> Result { - let mut builder = DidDocument::builder(did.clone()); - - for (i, fingerprint) in authentication_fingerprints.iter().enumerate() { - let id = DidUrl::from_fragment((i + 1).to_string()) - .map_err(|err| format!("Error constructing did url from fragment, error: {:?}", err))?; - builder = builder.add_verification_method( - VerificationMethod::builder( - id, - did.clone(), - VerificationMethodType::Ed25519VerificationKey2018, - ) - .add_public_key_multibase(fingerprint.clone()) - .build(), - ); - } - - for service in &legacy_ddo.service { - builder = builder.add_service(service.clone()); - } - - Ok(builder.build()) -} - -// https://github.com/TimoGlastra/legacy-did-transformation -fn convert_legacy_ddo_to_new(legacy_ddo: LegacyDidDoc) -> Result { - let authentication_fingerprints = collect_authentication_fingerprints(&legacy_ddo)?; - let encoded_services = collect_encoded_services(&legacy_ddo); - let did = construct_peer_did(&authentication_fingerprints, &encoded_services)?; - construct_new_did_document(&legacy_ddo, &authentication_fingerprints, did) -} - -pub fn deserialize_legacy_or_new_diddoc_value(val: Value) -> Result { - match serde_json::from_value::(val.clone()) { - Ok(legacy_doc) => convert_legacy_ddo_to_new(legacy_doc), - Err(_err) => Ok(serde_json::from_value::(val).map_err(|err| { - format!( - "Error deserializing did document from value, error: {:?}", - err - ) - })?), - } -} - -pub fn deserialize_legacy_or_new_diddoc_str(val: String) -> Result { - let value = serde_json::from_str::(&val) - .map_err(|err| format!("Error deserializing did doc value, error: {:?}", err))?; - deserialize_legacy_or_new_diddoc_value(value) -} - -#[cfg(test)] -mod tests { - use crate::schema::{ - did_doc::DidDocument, legacy::deserialize_legacy_or_new_diddoc_str, - service::service_key_kind::ServiceKeyKind, - }; - - const LEGACY_DID_DOC_JSON: &str = r#" - { - "id": "2ZHFFhzA2XtTD6hJqzL7ux", - "publicKey": [ - { - "id": "1", - "type": "Ed25519VerificationKey2018", - "controller": "2ZHFFhzA2XtTD6hJqzL7ux", - "publicKeyBase58": "rCw3x5h1jS6gPo7rRrt3EYbXXe5nNjnGbdf1jAwUxuj" - } - ], - "authentication": [ - { - "type": "Ed25519SignatureAuthentication2018", - "publicKey": "2ZHFFhzA2XtTD6hJqzL7ux#1" - } - ], - "service": [ - { - "id": "did:example:123456789abcdefghi;indy", - "type": "IndyAgent", - "priority": 0, - "recipientKeys": [ - "2ZHFFhzA2XtTD6hJqzL7ux#1" - ], - "routingKeys": [ - "8Ps2WosJ9AV1eXPoJKsEJdM3NchPhSyS8qFt6LQUTKv2", - "Hezce2UWMZ3wUhVkh2LfKSs8nDzWwzs2Win7EzNN3YaR" - ], - "serviceEndpoint": "http://localhost:8080/agency/msg" - } - ] - }"#; - - const VERKEY_BASE58: &str = "6MkfJTyeCL8MGvZntdpXzpitL6bM6uwCFz8xcYar18xQBh7"; - - const DID_PEER: &str = "did:peer:2.Vz6MkfJTyeCL8MGvZntdpXzpitL6bM6uwCFz8xcYar18xQBh7.SeyJwcmlvcml0eSI6MCwiciI6WyI4UHMyV29zSjlBVjFlWFBvSktzRUpkTTNOY2hQaFN5UzhxRnQ2TFFVVEt2MiIsIkhlemNlMlVXTVozd1VoVmtoMkxmS1NzOG5Eeld3enMyV2luN0V6Tk4zWWFSIl0sInJlY2lwaWVudEtleXMiOlsiMlpIRkZoekEyWHRURDZoSnF6TDd1eCMxIl0sInMiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYWdlbmN5L21zZyIsInQiOiJJbmR5QWdlbnQifQ"; - - #[test] - fn test_deserialization_legacy() { - let did_doc: DidDocument = - deserialize_legacy_or_new_diddoc_str(LEGACY_DID_DOC_JSON.into()).unwrap(); - assert_eq!(did_doc.id().to_string(), DID_PEER); - assert_eq!(did_doc.verification_method().len(), 1); - assert_eq!(did_doc.authentication().len(), 0); - assert_eq!(did_doc.assertion_method().len(), 0); - assert_eq!(did_doc.key_agreement().len(), 0); - assert_eq!(did_doc.service().len(), 1); - - let verification_method = did_doc.verification_method().first().unwrap(); - assert_eq!(verification_method.id().to_string(), "#1"); - assert_eq!(verification_method.controller().to_string(), DID_PEER); - assert_eq!( - verification_method - .public_key() - .unwrap() - .prefixless_fingerprint(), - VERKEY_BASE58 - ); - - let service = did_doc.service().first().unwrap(); - assert_eq!( - service.id().to_string(), - "did:example:123456789abcdefghi;indy" - ); - assert_eq!( - service.service_endpoint().to_string().as_str(), - "http://localhost:8080/agency/msg" - ); - - let recipient_key = match service - .extra_field_recipient_keys() - .unwrap() - .first() - .unwrap() - { - ServiceKeyKind::Reference(did_url) => did_doc - .dereference_key(did_url) - .unwrap() - .public_key() - .unwrap() - .prefixless_fingerprint(), - _ => panic!("Expected reference"), - }; - assert_eq!(recipient_key, VERKEY_BASE58); - assert_eq!(service.extra_field_priority().unwrap(), 0); - assert_eq!(service.extra_field_routing_keys().unwrap().len(), 2); - } -} diff --git a/did_core/did_doc/src/schema/mod.rs b/did_core/did_doc/src/schema/mod.rs index b9d1f4635d..bca3088b80 100644 --- a/did_core/did_doc/src/schema/mod.rs +++ b/did_core/did_doc/src/schema/mod.rs @@ -1,5 +1,4 @@ pub mod did_doc; -pub mod legacy; pub mod service; pub mod types; pub mod utils; diff --git a/did_core/did_doc/src/schema/verification_method/mod.rs b/did_core/did_doc/src/schema/verification_method/mod.rs index bf76b9ec8f..0e046a55e3 100644 --- a/did_core/did_doc/src/schema/verification_method/mod.rs +++ b/did_core/did_doc/src/schema/verification_method/mod.rs @@ -6,13 +6,14 @@ mod verification_method_type; use ::public_key::Key; use did_parser_nom::{Did, DidUrl}; use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; pub use verification_method_kind::VerificationMethodKind; pub use verification_method_type::VerificationMethodType; pub use self::public_key::PublicKeyField; -use crate::{error::DidDocumentBuilderError, schema::types::jsonwebkey::JsonWebKey}; +use crate::error::DidDocumentBuilderError; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, TypedBuilder)] #[serde(rename_all = "camelCase")] pub struct VerificationMethod { id: DidUrl, @@ -24,14 +25,6 @@ pub struct VerificationMethod { } impl VerificationMethod { - pub fn builder( - id: DidUrl, - controller: Did, - verification_method_type: VerificationMethodType, - ) -> IncompleteVerificationMethodBuilder { - IncompleteVerificationMethodBuilder::new(id, controller, verification_method_type) - } - pub fn id(&self) -> &DidUrl { &self.id } @@ -56,127 +49,6 @@ impl VerificationMethod { } } -#[derive(Debug, Clone)] -pub struct IncompleteVerificationMethodBuilder { - id: DidUrl, - controller: Did, - verification_method_type: VerificationMethodType, -} - -#[derive(Debug, Clone)] -pub struct CompleteVerificationMethodBuilder { - id: DidUrl, - controller: Did, - verification_method_type: VerificationMethodType, - public_key: Option, -} - -impl IncompleteVerificationMethodBuilder { - pub fn new( - id: DidUrl, - controller: Did, - verification_method_type: VerificationMethodType, - ) -> Self { - Self { - id, - verification_method_type, - controller, - } - } - - pub fn add_public_key_field( - self, - public_key: PublicKeyField, - ) -> CompleteVerificationMethodBuilder { - CompleteVerificationMethodBuilder { - id: self.id, - controller: self.controller, - verification_method_type: self.verification_method_type, - public_key: Some(public_key), - } - } - - pub fn add_public_key_multibase( - self, - public_key_multibase: String, - ) -> CompleteVerificationMethodBuilder { - CompleteVerificationMethodBuilder { - id: self.id, - controller: self.controller, - verification_method_type: self.verification_method_type, - public_key: Some(PublicKeyField::Multibase { - public_key_multibase, - }), - } - } - - pub fn add_public_key_jwk( - self, - public_key_jwk: JsonWebKey, - ) -> CompleteVerificationMethodBuilder { - CompleteVerificationMethodBuilder { - id: self.id, - controller: self.controller, - verification_method_type: self.verification_method_type, - public_key: Some(PublicKeyField::Jwk { public_key_jwk }), - } - } - - pub fn add_public_key_base58( - self, - public_key_base58: String, - ) -> CompleteVerificationMethodBuilder { - CompleteVerificationMethodBuilder { - id: self.id, - controller: self.controller, - verification_method_type: self.verification_method_type, - public_key: Some(PublicKeyField::Base58 { public_key_base58 }), - } - } - - pub fn add_public_key_base64( - self, - public_key_base64: String, - ) -> CompleteVerificationMethodBuilder { - CompleteVerificationMethodBuilder { - id: self.id, - controller: self.controller, - verification_method_type: self.verification_method_type, - public_key: Some(PublicKeyField::Base64 { public_key_base64 }), - } - } - - pub fn add_public_key_hex(self, public_key_hex: String) -> CompleteVerificationMethodBuilder { - CompleteVerificationMethodBuilder { - id: self.id, - controller: self.controller, - verification_method_type: self.verification_method_type, - public_key: Some(PublicKeyField::Hex { public_key_hex }), - } - } - - pub fn add_public_key_pem(self, public_key_pem: String) -> CompleteVerificationMethodBuilder { - CompleteVerificationMethodBuilder { - id: self.id, - controller: self.controller, - verification_method_type: self.verification_method_type, - public_key: Some(PublicKeyField::Pem { public_key_pem }), - } - } -} - -impl CompleteVerificationMethodBuilder { - pub fn build(self) -> VerificationMethod { - VerificationMethod { - id: self.id, - controller: self.controller, - verification_method_type: self.verification_method_type, - public_key: self.public_key.unwrap(), /* SAFETY: The builder will always set the - * public key */ - } - } -} - #[cfg(test)] mod tests { use serde_json::Value; @@ -222,18 +94,6 @@ mod tests { }) } - #[test] - fn test_verification_method_id() { - let id = create_valid_did_url(); - let controller = create_valid_did(); - let verification_method_type = create_valid_verification_key_type(); - let verification_method = - VerificationMethod::builder(id.clone(), controller, verification_method_type) - .add_public_key_multibase(create_valid_multibase()) - .build(); - assert_eq!(verification_method.id(), &id); - } - #[test] fn test_verification_method_builder() { let id = create_valid_did_url(); @@ -241,35 +101,14 @@ mod tests { let verification_method_type = create_valid_verification_key_type(); let public_key_multibase = create_valid_multibase(); - let vm = - VerificationMethod::builder(id.clone(), controller.clone(), verification_method_type) - .add_public_key_multibase(public_key_multibase) - .build(); - - assert_eq!(vm.id(), &id); - assert_eq!(vm.controller(), &controller); - assert_eq!(vm.verification_method_type(), &verification_method_type); - match vm.public_key_field() { - PublicKeyField::Multibase { + let vm = VerificationMethod::builder() + .id(id.clone()) + .controller(controller.clone()) + .verification_method_type(verification_method_type) + .public_key(PublicKeyField::Multibase { public_key_multibase, - } => { - assert_eq!(public_key_multibase, public_key_multibase) - } - _ => panic!("Expected public key to be multibase"), - } - } - - #[test] - fn test_verification_method_builder_complete() { - let id = create_valid_did_url(); - let controller = create_valid_did(); - let verification_method_type = create_valid_verification_key_type(); - let public_key_multibase = create_valid_multibase(); - - let vm = - VerificationMethod::builder(id.clone(), controller.clone(), verification_method_type) - .add_public_key_multibase(public_key_multibase) - .build(); + }) + .build(); assert_eq!(vm.id(), &id); assert_eq!(vm.controller(), &controller); @@ -303,31 +142,4 @@ mod tests { ); assert!(vm.is_err()); } - - #[test] - fn test_verification_method_public_key() { - let id = create_valid_did_url(); - let controller = create_valid_did(); - let verification_method_type = create_valid_verification_key_type(); - let public_key_multibase_expected = create_valid_multibase(); - - let vm = VerificationMethod::builder(id, controller, verification_method_type) - .add_public_key_multibase(public_key_multibase_expected.clone()) - .build(); - - match vm.public_key_field() { - PublicKeyField::Multibase { - public_key_multibase, - } => { - assert_eq!( - public_key_multibase.to_string(), - public_key_multibase_expected - ) - } - _ => panic!("Expected public key to be multibase"), - } - - let public_key = vm.public_key().unwrap(); - assert_eq!(public_key.multibase58(), public_key_multibase_expected); - } } diff --git a/did_core/did_methods/did_peer/Cargo.toml b/did_core/did_methods/did_peer/Cargo.toml index 91279a4887..94d82fd602 100644 --- a/did_core/did_methods/did_peer/Cargo.toml +++ b/did_core/did_methods/did_peer/Cargo.toml @@ -25,6 +25,7 @@ log = "0.4.16" url = { version = "2.3.1", features = ["serde"] } display_as_json = { path = "../../../misc/display_as_json" } derive_builder = "0.12.0" +typed-builder = "0.16.0" [dev-dependencies] tokio = { version = "1.27.0", default-features = false, features = ["macros", "rt"] } diff --git a/did_core/did_methods/did_peer/examples/demo.rs b/did_core/did_methods/did_peer/examples/demo.rs index 3fe6cfc0de..9593d4aeb0 100644 --- a/did_core/did_methods/did_peer/examples/demo.rs +++ b/did_core/did_methods/did_peer/examples/demo.rs @@ -5,7 +5,7 @@ use did_doc::schema::{ service::{typed::ServiceType, Service}, types::uri::Uri, utils::OneOrList, - verification_method::{VerificationMethod, VerificationMethodType}, + verification_method::{PublicKeyField, VerificationMethod, VerificationMethodType}, }; use did_parser_nom::{Did, DidUrl}; use did_peer::{ @@ -29,13 +29,14 @@ async fn main() -> Result<(), Box> { async fn demo_did_peer_2_and_3() -> Result<(), Box> { let did_url = DidUrl::parse("did:foo:bar#key-1".into())?; let did = Did::parse("did:foo:bar".into())?; - let verification_method = VerificationMethod::builder( - did_url, - did.clone(), - VerificationMethodType::Ed25519VerificationKey2018, - ) - .add_public_key_base64("Zm9vYmFyCg".to_string()) - .build(); + let verification_method = VerificationMethod::builder() + .id(did_url) + .controller(did.clone()) + .verification_method_type(VerificationMethodType::Ed25519VerificationKey2018) + .public_key(PublicKeyField::Base64 { + public_key_base64: "Zm9vYmFyCg".to_string(), + }) + .build(); let ddo = DidDocument::builder(did) .add_verification_method(verification_method) diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs index 8df3ae8117..5e24028ec5 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs @@ -132,9 +132,9 @@ mod tests { }, types::uri::Uri, utils::OneOrList, - verification_method::{VerificationMethod, VerificationMethodType}, + verification_method::{PublicKeyField, VerificationMethod, VerificationMethodType}, }; - use did_parser_nom::DidUrl; + use did_parser_nom::{Did, DidUrl}; use pretty_assertions::assert_eq; use super::*; @@ -150,13 +150,14 @@ mod tests { key: String, verification_type: VerificationMethodType, ) -> VerificationMethod { - VerificationMethod::builder( - verification_method_id.parse().unwrap(), - controller_did.parse().unwrap(), - verification_type, - ) - .add_public_key_multibase(key) - .build() + VerificationMethod::builder() + .id(verification_method_id.parse().unwrap()) + .controller(Did::parse(controller_did).unwrap()) + .verification_method_type(verification_type) + .public_key(PublicKeyField::Multibase { + public_key_multibase: key, + }) + .build() } #[test] diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs index 7ff0b0397c..d493b25cde 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs @@ -1,5 +1,5 @@ use did_doc::schema::verification_method::{ - IncompleteVerificationMethodBuilder, VerificationMethod, VerificationMethodType, + PublicKeyField, VerificationMethod, VerificationMethodType, }; use did_parser_nom::{Did, DidUrl}; use public_key::{Key, KeyType}; @@ -62,11 +62,13 @@ fn build_verification_methods_from_type_and_key( did: Did, public_key_encoding: PublicKeyEncoding, ) -> Vec { - vec![add_public_key_to_builder( - VerificationMethod::builder(id, did, vm_type), - key, - public_key_encoding, - )] + let vm = VerificationMethod::builder() + .id(id) + .controller(did.to_owned()) + .verification_method_type(vm_type) + .public_key(key_to_key_field(key, public_key_encoding)) + .build(); + vec![vm] } fn build_verification_methods_from_bls_multikey( @@ -77,32 +79,29 @@ fn build_verification_methods_from_bls_multikey( ) -> Vec { let id1 = to_did_url_reference(g1_key).unwrap(); let id2 = to_did_url_reference(g2_key).unwrap(); - - let vm1 = add_public_key_to_builder( - VerificationMethod::builder( - id1, - did.to_owned(), - VerificationMethodType::Bls12381G1Key2020, - ), - g1_key, - public_key_encoding, - ); - let vm2 = add_public_key_to_builder( - VerificationMethod::builder(id2, did, VerificationMethodType::Bls12381G2Key2020), - g2_key, - public_key_encoding, - ); + let vm1 = VerificationMethod::builder() + .id(id1) + .controller(did.to_owned()) + .verification_method_type(VerificationMethodType::Bls12381G1Key2020) + .public_key(key_to_key_field(g1_key, public_key_encoding)) + .build(); + let vm2 = VerificationMethod::builder() + .id(id2) + .controller(did.to_owned()) + .verification_method_type(VerificationMethodType::Bls12381G2Key2020) + .public_key(key_to_key_field(g2_key, public_key_encoding)) + .build(); vec![vm1, vm2] } -fn add_public_key_to_builder( - builder: IncompleteVerificationMethodBuilder, - key: &Key, - public_key_encoding: PublicKeyEncoding, -) -> VerificationMethod { +fn key_to_key_field(key: &Key, public_key_encoding: PublicKeyEncoding) -> PublicKeyField { match public_key_encoding { - PublicKeyEncoding::Base58 => builder.add_public_key_base58(key.base58()).build(), - PublicKeyEncoding::Multibase => builder.add_public_key_multibase(key.fingerprint()).build(), + PublicKeyEncoding::Base58 => PublicKeyField::Base58 { + public_key_base58: key.base58(), + }, + PublicKeyEncoding::Multibase => PublicKeyField::Multibase { + public_key_multibase: key.fingerprint(), + }, } } @@ -118,7 +117,9 @@ fn to_did_url_reference(key: &Key) -> Result { #[cfg(test)] mod tests { - use did_doc::schema::verification_method::{VerificationMethod, VerificationMethodType}; + use did_doc::schema::verification_method::{ + PublicKeyField, VerificationMethod, VerificationMethodType, + }; use did_parser_nom::Did; use public_key::Key; @@ -143,33 +144,36 @@ mod tests { } fn verification_method_0() -> VerificationMethod { - VerificationMethod::builder( - did().into(), - did(), - VerificationMethodType::X25519KeyAgreementKey2020, - ) - .add_public_key_multibase(key_0().fingerprint()) - .build() + VerificationMethod::builder() + .id(did().into()) + .controller(did()) + .verification_method_type(VerificationMethodType::X25519KeyAgreementKey2020) + .public_key(PublicKeyField::Multibase { + public_key_multibase: key_0().fingerprint(), + }) + .build() } fn verification_method_1() -> VerificationMethod { - VerificationMethod::builder( - did().into(), - did(), - VerificationMethodType::Ed25519VerificationKey2020, - ) - .add_public_key_multibase(key_1().fingerprint()) - .build() + VerificationMethod::builder() + .id(did().into()) + .controller(did()) + .verification_method_type(VerificationMethodType::Ed25519VerificationKey2020) + .public_key(PublicKeyField::Multibase { + public_key_multibase: key_1().fingerprint(), + }) + .build() } fn verification_method_2() -> VerificationMethod { - VerificationMethod::builder( - did().into(), - did(), - VerificationMethodType::Ed25519VerificationKey2020, - ) - .add_public_key_multibase(key_2().fingerprint()) - .build() + VerificationMethod::builder() + .id(did().into()) + .controller(did()) + .verification_method_type(VerificationMethodType::Ed25519VerificationKey2020) + .public_key(PublicKeyField::Multibase { + public_key_multibase: key_2().fingerprint(), + }) + .build() } mod get_verification_methods_by_key { diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/encoded_document.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/encoded_document.rs index d0cf9b96c5..7ae4c90c13 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/encoded_document.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/encoded_document.rs @@ -12,6 +12,7 @@ use did_parser_nom::DidUrl; use display_as_json::Display; use serde::{Deserialize, Serialize}; use serde_json::Value; +use typed_builder::TypedBuilder; use crate::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; @@ -87,32 +88,30 @@ impl DidPeer4VerificationMethodKind { } } -// TODO: use builder instead of pub(crate) ? -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, TypedBuilder)] #[serde(rename_all = "camelCase")] pub struct DidPeer4VerificationMethod { - pub(crate) id: DidUrl, + id: DidUrl, // - Controller MUST be relative, can we break down DidUrl into new type RelativeDidUrl? // - Controller MUST be omitted, if the controller is the document owner (main reason why this // is different from did_doc::schema::verification_method::VerificationMethod) // - TODO: add support for controller different than the document owner (how does that work for // peer DIDs?) - // controller: Option, + // pub(crate) controller: Option, #[serde(rename = "type")] - pub(crate) verification_method_type: VerificationMethodType, + verification_method_type: VerificationMethodType, #[serde(flatten)] - pub(crate) public_key: PublicKeyField, + public_key: PublicKeyField, } impl DidPeer4VerificationMethod { pub(crate) fn contextualize(&self, did_peer_4: &PeerDid) -> VerificationMethod { - VerificationMethod::builder( - self.id.clone(), - did_peer_4.did().clone(), - self.verification_method_type, - ) - .add_public_key_field(self.public_key.clone()) - .build() + VerificationMethod::builder() + .id(self.id.clone()) + .controller(did_peer_4.did().clone()) + .verification_method_type(self.verification_method_type) + .public_key(self.public_key.clone()) + .build() } } diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs index 95d3fd20a1..88aeb56e01 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs @@ -132,13 +132,14 @@ mod tests { OneOrList::One(ServiceType::DIDCommV2), HashMap::default(), ); - let vm = DidPeer4VerificationMethod { - id: DidUrl::parse("#key-1".to_string()).unwrap(), - verification_method_type: VerificationMethodType::Ed25519VerificationKey2020, - public_key: PublicKeyField::Base58 { + let vm = DidPeer4VerificationMethod::builder() + .id(DidUrl::parse("#key-1".to_string()).unwrap()) + .verification_method_type(VerificationMethodType::Ed25519VerificationKey2020) + .public_key(PublicKeyField::Base58 { public_key_base58: "z27uFkiq".to_string(), - }, - }; + }) + .build(); + let encoded_document = DidPeer4EncodedDocumentBuilder::default() .service(vec![service]) .verification_method(vec![vm]) diff --git a/did_core/did_methods/did_resolver_sov/src/dereferencing/utils.rs b/did_core/did_methods/did_resolver_sov/src/dereferencing/utils.rs index 6995cb4013..04e8578936 100644 --- a/did_core/did_methods/did_resolver_sov/src/dereferencing/utils.rs +++ b/did_core/did_methods/did_resolver_sov/src/dereferencing/utils.rs @@ -92,8 +92,10 @@ pub(crate) fn dereference_did_document( mod tests { use did_resolver::{ did_doc::schema::{ - did_doc::DidDocumentBuilder, service::typed::ServiceType, utils::OneOrList, - verification_method::VerificationMethodType, + did_doc::DidDocumentBuilder, + service::typed::ServiceType, + utils::OneOrList, + verification_method::{PublicKeyField, VerificationMethodType}, }, did_parser_nom::DidUrl, traits::resolvable::resolution_output::DidResolutionOutput, @@ -103,16 +105,14 @@ mod tests { use super::*; fn example_did_document_builder() -> DidDocumentBuilder { - let verification_method = VerificationMethod::builder( - DidUrl::parse("did:example:123456789abcdefghi#keys-1".to_string()).unwrap(), - "did:example:123456789abcdefghi" - .to_string() - .try_into() - .unwrap(), - VerificationMethodType::Ed25519VerificationKey2018, - ) - .add_public_key_base58("H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV".to_string()) - .build(); + let verification_method = VerificationMethod::builder() + .id(DidUrl::parse("did:example:123456789abcdefghi#keys-1".to_string()).unwrap()) + .controller("did:example:123456789abcdefghi".parse().unwrap()) + .verification_method_type(VerificationMethodType::Ed25519VerificationKey2018) + .public_key(PublicKeyField::Base58 { + public_key_base58: "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV".to_string(), + }) + .build(); let agent_service = Service::new( "did:example:123456789abcdefghi#agent".parse().unwrap(), diff --git a/did_core/did_methods/did_resolver_sov/src/resolution/utils.rs b/did_core/did_methods/did_resolver_sov/src/resolution/utils.rs index 556bba9718..372d3c7183 100644 --- a/did_core/did_methods/did_resolver_sov/src/resolution/utils.rs +++ b/did_core/did_methods/did_resolver_sov/src/resolution/utils.rs @@ -5,7 +5,7 @@ use did_resolver::{ service::{typed::ServiceType, Service}, types::uri::Uri, utils::OneOrList, - verification_method::{VerificationMethod, VerificationMethodType}, + verification_method::{PublicKeyField, VerificationMethod, VerificationMethodType}, }, did_parser_nom::{Did, DidUrl}, shared_types::did_document_metadata::DidDocumentMetadata, @@ -94,13 +94,14 @@ pub(super) async fn ledger_response_to_ddo( ); // TODO: Use multibase instead of base58 - let verification_method = VerificationMethod::builder( - DidUrl::parse("#1".to_string())?, - did.to_string().try_into()?, - VerificationMethodType::Ed25519VerificationKey2018, - ) - .add_public_key_base58(verkey) - .build(); + let verification_method = VerificationMethod::builder() + .id(DidUrl::parse("#1".to_string())?) + .controller(did.to_string().try_into()?) + .verification_method_type(VerificationMethodType::Ed25519VerificationKey2018) + .public_key(PublicKeyField::Base58 { + public_key_base58: verkey, + }) + .build(); let ddo = DidDocument::builder(ddo_id) .add_service(service) diff --git a/did_core/did_parser_nom/src/did_url/mod.rs b/did_core/did_parser_nom/src/did_url/mod.rs index fec258eac6..763f9a34f2 100644 --- a/did_core/did_parser_nom/src/did_url/mod.rs +++ b/did_core/did_parser_nom/src/did_url/mod.rs @@ -21,6 +21,7 @@ pub struct DidUrl { } impl DidUrl { + // todo: can be &str pub fn parse(did_url: String) -> Result { parse_did_url(did_url) }