diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f0f6cf3775..85b194b4d0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -110,7 +110,7 @@ jobs: sudo apt-get install -y libsodium-dev libssl-dev libzmq3-dev - name: "Verify clippy across the entire workspace with default features" run: | - cargo clippy --tests --all-features + cargo clippy --examples --tests --all-features env: RUSTFLAGS: -D warnings @@ -354,7 +354,7 @@ jobs: rust-toolchain-version: ${{ env.RUST_TOOLCHAIN_VERSON }} - name: "Run resolver tests" run: | - RUST_TEST_THREADS=1 cargo test -p did_doc -p did_parser -p did_resolver -p did_resolver_registry -p did_resolver_sov -p did_resolver_web -p did_doc_sov -p did_key -p did_peer --test "*" + RUST_TEST_THREADS=1 cargo test --examples -p did_doc -p did_parser -p did_resolver -p did_resolver_registry -p did_resolver_sov -p did_resolver_web -p did_doc_sov -p did_key -p did_peer --test "*" test-integration-node-wrapper: needs: workflow-setup diff --git a/Cargo.lock b/Cargo.lock index 169261f074..ddc8d0e4e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1420,6 +1420,7 @@ dependencies = [ "base64", "did_doc", "did_key", + "display_as_json", "public_key", "serde", "serde_json", @@ -1456,6 +1457,7 @@ dependencies = [ "did_doc_sov", "did_parser", "did_resolver", + "display_as_json", "multibase", "once_cell", "public_key", @@ -1576,6 +1578,17 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "display_as_json" +version = "0.1.0" +dependencies = [ + "quote", + "serde", + "serde_derive", + "serde_json", + "syn 1.0.109", +] + [[package]] name = "dotenvy" version = "0.15.7" diff --git a/Cargo.toml b/Cargo.toml index 72d5ba16b1..b99e8e14d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,8 @@ members = [ "wallet_migrator", "tools/simple_message_relay", "tools/test_utils", - "tools/libvcx_logger" + "tools/libvcx_logger", + "tools/display_as_json" ] [workspace.package] diff --git a/did_doc/src/schema/did_doc.rs b/did_doc/src/schema/did_doc.rs index f4669b681a..d5ea72df97 100644 --- a/did_doc/src/schema/did_doc.rs +++ b/did_doc/src/schema/did_doc.rs @@ -42,7 +42,10 @@ pub struct DidDocument { extra: HashMap, } -impl Display for DidDocument<()> { +impl Display for DidDocument +where + E: Display + Serialize, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let json = serde_json::to_string(self).unwrap(); write!(f, "{}", json) diff --git a/did_doc_sov/Cargo.toml b/did_doc_sov/Cargo.toml index 1040459e7c..3fde2a1dab 100644 --- a/did_doc_sov/Cargo.toml +++ b/did_doc_sov/Cargo.toml @@ -11,3 +11,4 @@ public_key = { path = "../public_key" } # TODO: Remove after transition to new D serde = { version = "1.0.159", default-features = false, features = ["derive"] } serde_json = "1.0.95" thiserror = "1.0.40" +display_as_json = { path = "../tools/display_as_json" } diff --git a/did_doc_sov/src/extra_fields/aip1.rs b/did_doc_sov/src/extra_fields/aip1.rs index 0ec8e4f44c..4f1d13ee57 100644 --- a/did_doc_sov/src/extra_fields/aip1.rs +++ b/did_doc_sov/src/extra_fields/aip1.rs @@ -1,5 +1,6 @@ +use display_as_json::Display; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, Display)] #[serde(deny_unknown_fields)] pub struct ExtraFieldsAIP1 {} diff --git a/did_doc_sov/src/extra_fields/didcommv1.rs b/did_doc_sov/src/extra_fields/didcommv1.rs index 393cbb1821..ca2a5c0b32 100644 --- a/did_doc_sov/src/extra_fields/didcommv1.rs +++ b/did_doc_sov/src/extra_fields/didcommv1.rs @@ -1,8 +1,9 @@ +use display_as_json::Display; use serde::{Deserialize, Serialize}; use super::{AcceptType, KeyKind}; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, Display)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct ExtraFieldsDidCommV1 { diff --git a/did_doc_sov/src/extra_fields/didcommv2.rs b/did_doc_sov/src/extra_fields/didcommv2.rs index e66390dfb2..bef7cef365 100644 --- a/did_doc_sov/src/extra_fields/didcommv2.rs +++ b/did_doc_sov/src/extra_fields/didcommv2.rs @@ -1,8 +1,9 @@ +use display_as_json::Display; use serde::{Deserialize, Serialize}; use super::{AcceptType, KeyKind}; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, Display)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct ExtraFieldsDidCommV2 { diff --git a/did_doc_sov/src/extra_fields/legacy.rs b/did_doc_sov/src/extra_fields/legacy.rs index e90b0f1b50..6947989070 100644 --- a/did_doc_sov/src/extra_fields/legacy.rs +++ b/did_doc_sov/src/extra_fields/legacy.rs @@ -1,8 +1,9 @@ +use display_as_json::Display; use serde::{Deserialize, Serialize}; use super::KeyKind; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, Display)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct ExtraFieldsLegacy { diff --git a/did_doc_sov/src/extra_fields/mod.rs b/did_doc_sov/src/extra_fields/mod.rs index baeb99f9fb..2ae0aaa7d7 100644 --- a/did_doc_sov/src/extra_fields/mod.rs +++ b/did_doc_sov/src/extra_fields/mod.rs @@ -83,7 +83,7 @@ impl Display for KeyKind { } } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, display_as_json::Display)] #[serde(untagged)] pub enum ExtraFieldsSov { DIDCommV1(didcommv1::ExtraFieldsDidCommV1), diff --git a/did_doc_sov/src/lib.rs b/did_doc_sov/src/lib.rs index 8d4077bb6f..5c9491a4a5 100644 --- a/did_doc_sov/src/lib.rs +++ b/did_doc_sov/src/lib.rs @@ -1,3 +1,5 @@ +extern crate display_as_json; + pub mod error; pub mod extra_fields; // TODO: Remove once migration is done diff --git a/did_peer/Cargo.toml b/did_peer/Cargo.toml index ef31566126..911a16ab58 100644 --- a/did_peer/Cargo.toml +++ b/did_peer/Cargo.toml @@ -22,6 +22,7 @@ multibase = "0.9.1" unsigned-varint = "0.7.1" once_cell = "1.18.0" sha256 = "1.1.4" +display_as_json = { path = "../tools/display_as_json" } [dev-dependencies] tokio = { version = "1.27.0", default-features = false, features = ["macros", "rt"] } diff --git a/did_peer/README.md b/did_peer/README.md new file mode 100644 index 0000000000..033f6b37a3 --- /dev/null +++ b/did_peer/README.md @@ -0,0 +1,31 @@ +# did_peer + +## Overview +Rust crate for creation, parsing, validation, and resolution of [Peer DIDs](https://identity.foundation/peer-did-method-spec). +Peer DIDs are a special type of decentralized identifiers designed for direct peer-to-peer interactions, without the +need for a blockchain or other centralized registry. + +## Features +- **Numalgo Support**: The library implements various version of did:peer. The different versions are referred to as "numalgos". + Currently supports numalgo 1, 2, and 3. +- **DID Parsing**: Capability to parse `did:peer` strings, ensuring they comply with the Peer DID specifications. +- **DID Creation from DIDDoc**: Functionality to create `did:peer` identifiers from DID documents. +- **Numalgo Conversion**: Ability to convert between different numalgos, specifically from Numalgo 2 to Numalgo 3. +- **Validation**: Verification that DIDs adhere to the required specifications and format. + +## Getting Started +### Installation +Add the Peer DID library as a dependency in your `Cargo.toml` file: +```toml +[dependencies] +peer_did = { tag = "0.61.0", git = "https://github.com/hyperledger/aries-vcx" } +``` + +## Demo +To get you off the ground, have a look at the [demo](./examples/demo.rs). It demonstrates how to create, parse. You can +run the demo with the following command: +```bash +cargo run --example demo +``` + + diff --git a/did_peer/examples/demo.rs b/did_peer/examples/demo.rs new file mode 100644 index 0000000000..2a41cca295 --- /dev/null +++ b/did_peer/examples/demo.rs @@ -0,0 +1,69 @@ +use std::error::Error; + +use did_doc::schema::{ + did_doc::DidDocument, + service::ServiceBuilder, + types::{uri::Uri, url::Url}, + verification_method::{VerificationMethod, VerificationMethodType}, +}; +use did_doc_sov::extra_fields::{didcommv1::ExtraFieldsDidCommV1, ExtraFieldsSov, KeyKind}; +use did_parser::{Did, DidUrl}; +use did_peer::peer_did::{ + numalgos::{numalgo2::Numalgo2, numalgo3::Numalgo3}, + PeerDid, +}; + +fn main() -> Result<(), Box> { + demo() +} + +fn demo() -> Result<(), Box> { + let recipient_key = KeyKind::Value("foo".to_string()); + let sov_service_extra = ExtraFieldsSov::DIDCommV1( + ExtraFieldsDidCommV1::builder() + .set_recipient_keys(vec![recipient_key]) + .build(), + ); + let service = ServiceBuilder::::new( + Uri::new("xyz://example.org")?, + Url::new("http://example.org")?, + sov_service_extra, + ) + .add_service_type("DIDCommMessaging".to_string())? + .build(); + + 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 ddo = DidDocument::builder(did) + .add_verification_method(verification_method) + .add_service(service) + .build(); + println!("Did document: \n{}", serde_json::to_string_pretty(&ddo)?); + + let peer_did_2 = PeerDid::::from_did_doc(ddo.clone())?; + println!("as did:peer numalgo(2): {}", peer_did_2); + + let peer_did_3 = PeerDid::::from_did_doc(ddo)?; + println!("as did:peer numalgo(3): {}", peer_did_3); + + let peer_did_3_v2 = peer_did_2.to_numalgo3()?; + println!( + "as did:peer numalgo(2) converted to numalgo(3): {}", + peer_did_3_v2 + ); + + Ok(()) +} + +#[test] +fn demo_test() -> Result<(), Box> { + demo() +} diff --git a/did_peer/src/error.rs b/did_peer/src/error.rs index 62d9d9be12..d47b5b74fa 100644 --- a/did_peer/src/error.rs +++ b/did_peer/src/error.rs @@ -3,7 +3,7 @@ use std::convert::Infallible; use did_doc::schema::verification_method::VerificationMethodType; use thiserror::Error; -use crate::peer_did::numalgos::NumalgoKind; +use crate::peer_did::numalgos::kind::NumalgoKind; #[derive(Debug, Error)] pub enum DidPeerError { diff --git a/did_peer/src/lib.rs b/did_peer/src/lib.rs index 3cf6323b0b..462a582971 100644 --- a/did_peer/src/lib.rs +++ b/did_peer/src/lib.rs @@ -1,4 +1,5 @@ +extern crate display_as_json; + pub mod error; -mod numalgos; pub mod peer_did; -pub mod peer_did_resolver; +pub mod resolver; diff --git a/did_peer/src/numalgos/mod.rs b/did_peer/src/numalgos/mod.rs deleted file mode 100644 index 0f8a93b0a0..0000000000 --- a/did_peer/src/numalgos/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod numalgo2; -pub mod numalgo3; diff --git a/did_peer/src/numalgos/numalgo2/generate/mod.rs b/did_peer/src/numalgos/numalgo2/generate/mod.rs deleted file mode 100644 index b28593f51b..0000000000 --- a/did_peer/src/numalgos/numalgo2/generate/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -mod helpers; - -use did_doc::schema::did_doc::DidDocument; -use did_doc_sov::extra_fields::ExtraFieldsSov; - -use self::helpers::{append_encoded_key_segments, append_encoded_service_segment}; -use crate::{ - error::DidPeerError, - peer_did::{numalgos::numalgo2::Numalgo2, PeerDid}, -}; - -pub fn generate_numalgo2( - did_document: DidDocument, -) -> Result, DidPeerError> { - let mut did = String::from("did:peer:2"); - - did = append_encoded_key_segments(did, &did_document)?; - did = append_encoded_service_segment(did, &did_document)?; - - PeerDid::::parse(did) -} diff --git a/did_peer/src/numalgos/numalgo2/mod.rs b/did_peer/src/numalgos/numalgo2/mod.rs deleted file mode 100644 index d2822f8f8e..0000000000 --- a/did_peer/src/numalgos/numalgo2/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod generate; -mod purpose; -mod resolve; -mod service_abbreviated; -mod verification_method; - -pub use generate::generate_numalgo2; -pub use resolve::resolve_numalgo2; diff --git a/did_peer/src/numalgos/numalgo3/generate.rs b/did_peer/src/numalgos/numalgo3/generate.rs deleted file mode 100644 index f061969161..0000000000 --- a/did_peer/src/numalgos/numalgo3/generate.rs +++ /dev/null @@ -1,35 +0,0 @@ -use did_parser::Did; -use sha256::digest; - -use crate::{ - error::DidPeerError, - peer_did::{numalgos::numalgo3::Numalgo3, PeerDid}, -}; - -pub fn generate_numalgo3(did: &Did) -> Result, DidPeerError> { - let numalgoless_id = did.id().chars().skip(2).collect::(); - let numalgoless_id_hashed = digest(numalgoless_id); - PeerDid::::parse(format!("did:peer:3.{}", numalgoless_id_hashed)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_generate_numalgo3() { - let peer_did_2 = Did::parse("did:peer:2\ - .Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc\ - .Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V\ - .Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg\ - .SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0".to_string()).unwrap(); - assert_eq!( - PeerDid::::parse( - "did:peer:3.0e857e93798921e83cfc2ef8bee9cafc25f15f4c9c7bee5ed9a9c62b56a62cca" - .to_string() - ) - .unwrap(), - generate_numalgo3(&peer_did_2).unwrap() - ); - } -} diff --git a/did_peer/src/numalgos/numalgo3/mod.rs b/did_peer/src/numalgos/numalgo3/mod.rs deleted file mode 100644 index 8b1ee44df5..0000000000 --- a/did_peer/src/numalgos/numalgo3/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod generate; - -pub use generate::generate_numalgo3; diff --git a/did_peer/src/peer_did/generate.rs b/did_peer/src/peer_did/generate.rs deleted file mode 100644 index 4ab04e711f..0000000000 --- a/did_peer/src/peer_did/generate.rs +++ /dev/null @@ -1,23 +0,0 @@ -use did_doc::schema::did_doc::DidDocument; -use did_doc_sov::extra_fields::ExtraFieldsSov; - -use super::{ - numalgos::{numalgo2::Numalgo2, numalgo3::Numalgo3}, - PeerDid, -}; -use crate::{ - error::DidPeerError, - numalgos::{numalgo2, numalgo3}, -}; - -pub fn generate_numalgo2( - did_document: DidDocument, -) -> Result, DidPeerError> { - numalgo2::generate_numalgo2(did_document) -} - -pub fn generate_numalgo3( - did_document: DidDocument, -) -> Result, DidPeerError> { - numalgo3::generate_numalgo3(generate_numalgo2(did_document)?.did()) -} diff --git a/did_peer/src/peer_did/generic.rs b/did_peer/src/peer_did/generic.rs index 0c5cc9fb09..aa34844282 100644 --- a/did_peer/src/peer_did/generic.rs +++ b/did_peer/src/peer_did/generic.rs @@ -5,20 +5,20 @@ use super::PeerDid; use crate::{ error::DidPeerError, peer_did::{ - numalgos::{numalgo2::Numalgo2, numalgo3::Numalgo3, NumalgoKind}, + numalgos::{kind::NumalgoKind, numalgo2::Numalgo2, numalgo3::Numalgo3}, parse::parse_numalgo, validate::validate, }, }; #[derive(Clone, Debug, PartialEq)] -pub enum GenericPeerDid { +pub enum AnyPeerDid { Numalgo2(PeerDid), Numalgo3(PeerDid), } -impl GenericPeerDid { - pub fn parse(did: T) -> Result +impl AnyPeerDid { + pub fn parse(did: T) -> Result where Did: TryFrom, >::Error: Into, @@ -28,9 +28,9 @@ impl GenericPeerDid { validate(&did)?; let parsed = match numalgo { NumalgoKind::MultipleInceptionKeys(numalgo) => { - GenericPeerDid::Numalgo2(PeerDid { did, numalgo }) + AnyPeerDid::Numalgo2(PeerDid { did, numalgo }) } - _ => GenericPeerDid::Numalgo3(PeerDid { + _ => AnyPeerDid::Numalgo3(PeerDid { did, numalgo: Numalgo3, }), @@ -40,27 +40,25 @@ impl GenericPeerDid { pub fn numalgo(&self) -> NumalgoKind { match self { - GenericPeerDid::Numalgo2(peer_did) => { - NumalgoKind::MultipleInceptionKeys(peer_did.numalgo) - } - GenericPeerDid::Numalgo3(peer_did) => NumalgoKind::DidShortening(peer_did.numalgo), + AnyPeerDid::Numalgo2(peer_did) => NumalgoKind::MultipleInceptionKeys(peer_did.numalgo), + AnyPeerDid::Numalgo3(peer_did) => NumalgoKind::DidShortening(peer_did.numalgo), } } } -impl Serialize for GenericPeerDid { +impl Serialize for AnyPeerDid { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match &self { - GenericPeerDid::Numalgo2(peer_did) => serializer.serialize_str(peer_did.did().did()), - GenericPeerDid::Numalgo3(peer_did) => serializer.serialize_str(peer_did.did().did()), + AnyPeerDid::Numalgo2(peer_did) => serializer.serialize_str(peer_did.did().did()), + AnyPeerDid::Numalgo3(peer_did) => serializer.serialize_str(peer_did.did().did()), } } } -impl<'de> Deserialize<'de> for GenericPeerDid { +impl<'de> Deserialize<'de> for AnyPeerDid { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, @@ -88,15 +86,15 @@ mod tests { const INVALID_PEER_DID_NUMALGO3: &str = "did:peer:3.d8da5079c166b183cfz15ee27747f34e116977103d8b23c96dcba9a9d9429689"; - fn generic_peer_did_numalgo2() -> GenericPeerDid { - GenericPeerDid::Numalgo2(PeerDid { + fn generic_peer_did_numalgo2() -> AnyPeerDid { + AnyPeerDid::Numalgo2(PeerDid { did: VALID_PEER_DID_NUMALGO2.parse().unwrap(), numalgo: Numalgo2, }) } - fn generic_peer_did_numalgo3() -> GenericPeerDid { - GenericPeerDid::Numalgo3(PeerDid { + fn generic_peer_did_numalgo3() -> AnyPeerDid { + AnyPeerDid::Numalgo3(PeerDid { did: VALID_PEER_DID_NUMALGO3.parse().unwrap(), numalgo: Numalgo3, }) @@ -123,28 +121,28 @@ mod tests { #[test] fn numalgo2() { - let deserialized: GenericPeerDid = + let deserialized: AnyPeerDid = serde_json::from_str(&format!("\"{}\"", VALID_PEER_DID_NUMALGO2)).unwrap(); assert_eq!(deserialized, generic_peer_did_numalgo2()); } #[test] fn numalgo2_invalid() { - let deserialized: Result = + let deserialized: Result = serde_json::from_str(&format!("\"{}\"", INVALID_PEER_DID_NUMALGO2)); assert!(deserialized.is_err()); } #[test] fn numalgo3() { - let deserialized: GenericPeerDid = + let deserialized: AnyPeerDid = serde_json::from_str(&format!("\"{}\"", VALID_PEER_DID_NUMALGO3)).unwrap(); assert_eq!(deserialized, generic_peer_did_numalgo3()); } #[test] fn numalgo3_invalid() { - let deserialized: Result = + let deserialized: Result = serde_json::from_str(&format!("\"{}\"", INVALID_PEER_DID_NUMALGO3)); assert!(deserialized.is_err()); } diff --git a/did_peer/src/peer_did/mod.rs b/did_peer/src/peer_did/mod.rs index 8663120ec1..a1e651d637 100644 --- a/did_peer/src/peer_did/mod.rs +++ b/did_peer/src/peer_did/mod.rs @@ -1,8 +1,6 @@ -pub mod generate; pub mod numalgos; mod parse; -mod regex; mod validate; pub mod generic; @@ -10,17 +8,15 @@ pub mod generic; use core::fmt; use std::{fmt::Display, marker::PhantomData}; +use did_doc::schema::did_doc::DidDocument; +use did_doc_sov::extra_fields::ExtraFieldsSov; use did_parser::Did; -use numalgos::{ - numalgo3::Numalgo3, - traits::{Numalgo, ToNumalgo3}, -}; use serde::{ de::{self, Visitor}, Deserialize, Deserializer, Serialize, Serializer, }; -use crate::error::DidPeerError; +use crate::{error::DidPeerError, peer_did::numalgos::Numalgo}; #[derive(Clone, Debug, PartialEq)] pub struct PeerDid { @@ -46,9 +42,19 @@ impl PeerDid { } } -impl PeerDid { - pub fn to_numalgo3(&self) -> Result, DidPeerError> { - N::to_numalgo3(self.did()) +pub trait FromDidDoc: Numalgo { + fn from_did_doc( + did_document: DidDocument, + ) -> Result, DidPeerError> + where + Self: Sized; +} + +impl PeerDid { + pub fn from_did_doc( + did_document: DidDocument, + ) -> Result, DidPeerError> { + N::from_did_doc(did_document) } } @@ -105,7 +111,7 @@ impl From> for Did { #[cfg(test)] mod tests { use super::*; - use crate::peer_did::numalgos::numalgo2::Numalgo2; + use crate::peer_did::numalgos::{numalgo2::Numalgo2, numalgo3::Numalgo3}; const VALID_PEER_DID_NUMALGO2: &str = "did:peer:2\ .Ez6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH\ @@ -192,14 +198,6 @@ mod tests { peer_did_numalgo2().to_numalgo3().unwrap() ); } - - #[test] - fn numalgo3() { - assert_eq!( - peer_did_numalgo3(), - peer_did_numalgo3().to_numalgo3().unwrap() - ); - } } mod serialize { diff --git a/did_peer/src/peer_did/numalgos/kind.rs b/did_peer/src/peer_did/numalgos/kind.rs new file mode 100644 index 0000000000..732ea2fa7c --- /dev/null +++ b/did_peer/src/peer_did/numalgos/kind.rs @@ -0,0 +1,47 @@ +use std::fmt::Display; + +use crate::{ + error::DidPeerError, + peer_did::numalgos::{ + numalgo0::Numalgo0, numalgo1::Numalgo1, numalgo2::Numalgo2, numalgo3::Numalgo3, Numalgo, + }, +}; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum NumalgoKind { + InceptionKeyWithoutDoc(Numalgo0), + GenesisDoc(Numalgo1), + MultipleInceptionKeys(Numalgo2), + DidShortening(Numalgo3), +} + +impl NumalgoKind { + pub fn to_char(&self) -> char { + match self { + NumalgoKind::InceptionKeyWithoutDoc(_) => Numalgo0::NUMALGO_CHAR, + NumalgoKind::GenesisDoc(_) => Numalgo1::NUMALGO_CHAR, + NumalgoKind::MultipleInceptionKeys(_) => Numalgo2::NUMALGO_CHAR, + NumalgoKind::DidShortening(_) => Numalgo3::NUMALGO_CHAR, + } + } +} + +impl Display for NumalgoKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.to_char().fmt(f) + } +} + +impl TryFrom for NumalgoKind { + type Error = DidPeerError; + + fn try_from(value: char) -> Result { + match value { + Numalgo0::NUMALGO_CHAR => Ok(NumalgoKind::InceptionKeyWithoutDoc(Numalgo0)), + Numalgo1::NUMALGO_CHAR => Ok(NumalgoKind::GenesisDoc(Numalgo1)), + Numalgo2::NUMALGO_CHAR => Ok(NumalgoKind::MultipleInceptionKeys(Numalgo2)), + Numalgo3::NUMALGO_CHAR => Ok(NumalgoKind::DidShortening(Numalgo3)), + c => Err(DidPeerError::InvalidNumalgoCharacter(c)), + } + } +} diff --git a/did_peer/src/peer_did/numalgos/mod.rs b/did_peer/src/peer_did/numalgos/mod.rs index d816f9a468..2fa91049c6 100644 --- a/did_peer/src/peer_did/numalgos/mod.rs +++ b/did_peer/src/peer_did/numalgos/mod.rs @@ -1,55 +1,41 @@ +pub mod kind; pub mod numalgo0; pub mod numalgo1; pub mod numalgo2; pub mod numalgo3; -pub(super) mod traits; - -use std::fmt::Display; - -use numalgo0::Numalgo0; -use numalgo1::Numalgo1; -use numalgo2::Numalgo2; -use numalgo3::Numalgo3; - -use self::traits::Numalgo; -use crate::error::DidPeerError; - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum NumalgoKind { - InceptionKeyWithoutDoc(Numalgo0), - GenesisDoc(Numalgo1), - MultipleInceptionKeys(Numalgo2), - DidShortening(Numalgo3), -} - -impl NumalgoKind { - pub fn to_char(&self) -> char { - match self { - NumalgoKind::InceptionKeyWithoutDoc(_) => Numalgo0::NUMALGO_CHAR, - NumalgoKind::GenesisDoc(_) => Numalgo1::NUMALGO_CHAR, - NumalgoKind::MultipleInceptionKeys(_) => Numalgo2::NUMALGO_CHAR, - NumalgoKind::DidShortening(_) => Numalgo3::NUMALGO_CHAR, +use did_doc::schema::did_doc::DidDocument; +use did_doc_sov::extra_fields::ExtraFieldsSov; +use did_parser::Did; + +use crate::{ + error::DidPeerError, + peer_did::{parse::parse_numalgo, validate::validate, PeerDid}, + resolver::options::PublicKeyEncoding, +}; + +pub trait Numalgo: Sized + Default { + const NUMALGO_CHAR: char; + + fn parse(did: T) -> Result, DidPeerError> + where + Did: TryFrom, + >::Error: Into, + { + let did: Did = did.try_into().map_err(Into::into)?; + let numalgo_char = parse_numalgo(&did)?.to_char(); + if numalgo_char != Self::NUMALGO_CHAR { + return Err(DidPeerError::InvalidNumalgoCharacter(numalgo_char)); } + validate(&did)?; + Ok(PeerDid::from_parts(did, Self::default())) } } -impl Display for NumalgoKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.to_char().fmt(f) - } -} - -impl TryFrom for NumalgoKind { - type Error = DidPeerError; - - fn try_from(value: char) -> Result { - match value { - Numalgo0::NUMALGO_CHAR => Ok(NumalgoKind::InceptionKeyWithoutDoc(Numalgo0)), - Numalgo1::NUMALGO_CHAR => Ok(NumalgoKind::GenesisDoc(Numalgo1)), - Numalgo2::NUMALGO_CHAR => Ok(NumalgoKind::MultipleInceptionKeys(Numalgo2)), - Numalgo3::NUMALGO_CHAR => Ok(NumalgoKind::DidShortening(Numalgo3)), - c => Err(DidPeerError::InvalidNumalgoCharacter(c)), - } - } +pub trait ResolvableNumalgo: Numalgo { + fn resolve( + &self, + did: &Did, + public_key_encoding: PublicKeyEncoding, + ) -> Result, DidPeerError>; } diff --git a/did_peer/src/peer_did/numalgos/numalgo0.rs b/did_peer/src/peer_did/numalgos/numalgo0/mod.rs similarity index 77% rename from did_peer/src/peer_did/numalgos/numalgo0.rs rename to did_peer/src/peer_did/numalgos/numalgo0/mod.rs index 469949e76d..2b5e81e91e 100644 --- a/did_peer/src/peer_did/numalgos/numalgo0.rs +++ b/did_peer/src/peer_did/numalgos/numalgo0/mod.rs @@ -1,4 +1,4 @@ -use super::traits::Numalgo; +use crate::peer_did::numalgos::Numalgo; #[derive(Clone, Copy, Default, Debug, PartialEq)] pub struct Numalgo0; diff --git a/did_peer/src/peer_did/numalgos/numalgo1.rs b/did_peer/src/peer_did/numalgos/numalgo1/mod.rs similarity index 77% rename from did_peer/src/peer_did/numalgos/numalgo1.rs rename to did_peer/src/peer_did/numalgos/numalgo1/mod.rs index 0405dafea9..8a70427459 100644 --- a/did_peer/src/peer_did/numalgos/numalgo1.rs +++ b/did_peer/src/peer_did/numalgos/numalgo1/mod.rs @@ -1,4 +1,4 @@ -use super::traits::Numalgo; +use crate::peer_did::numalgos::Numalgo; #[derive(Clone, Copy, Default, Debug, PartialEq)] pub struct Numalgo1; diff --git a/did_peer/src/peer_did/numalgos/numalgo2.rs b/did_peer/src/peer_did/numalgos/numalgo2.rs deleted file mode 100644 index 209bd64faa..0000000000 --- a/did_peer/src/peer_did/numalgos/numalgo2.rs +++ /dev/null @@ -1,37 +0,0 @@ -use did_doc::schema::did_doc::DidDocument; -use did_doc_sov::extra_fields::ExtraFieldsSov; -use did_parser::Did; - -use super::{ - numalgo3::Numalgo3, - traits::{Numalgo, ResolvableNumalgo, ToNumalgo3}, -}; -use crate::{ - error::DidPeerError, - numalgos::{numalgo2::resolve_numalgo2, numalgo3::generate_numalgo3}, - peer_did::PeerDid, - peer_did_resolver::options::PublicKeyEncoding, -}; - -#[derive(Clone, Copy, Default, Debug, PartialEq)] -pub struct Numalgo2; - -impl Numalgo for Numalgo2 { - const NUMALGO_CHAR: char = '2'; -} - -impl ResolvableNumalgo for Numalgo2 { - fn resolve( - &self, - did: &Did, - public_key_encoding: PublicKeyEncoding, - ) -> Result, DidPeerError> { - resolve_numalgo2(did, public_key_encoding).map(|builder| builder.build()) - } -} - -impl ToNumalgo3 for Numalgo2 { - fn to_numalgo3(did: &Did) -> Result, DidPeerError> { - generate_numalgo3(did) - } -} diff --git a/did_peer/src/numalgos/numalgo2/generate/helpers.rs b/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs similarity index 99% rename from did_peer/src/numalgos/numalgo2/generate/helpers.rs rename to did_peer/src/peer_did/numalgos/numalgo2/encoding.rs index df4d9fcd96..96973af5c0 100644 --- a/did_peer/src/numalgos/numalgo2/generate/helpers.rs +++ b/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs @@ -12,7 +12,7 @@ use public_key::Key; use crate::{ error::DidPeerError, - numalgos::numalgo2::{ + peer_did::numalgos::numalgo2::{ purpose::ElementPurpose, service_abbreviated::ServiceAbbreviated, verification_method::get_key_by_verification_method, }, diff --git a/did_peer/src/peer_did/numalgos/numalgo2/mod.rs b/did_peer/src/peer_did/numalgos/numalgo2/mod.rs new file mode 100644 index 0000000000..2eaf3d0f99 --- /dev/null +++ b/did_peer/src/peer_did/numalgos/numalgo2/mod.rs @@ -0,0 +1,58 @@ +use did_doc::schema::did_doc::DidDocument; +use did_doc_sov::extra_fields::ExtraFieldsSov; +use did_parser::Did; +use encoding::{append_encoded_key_segments, append_encoded_service_segment}; +use sha256::digest; + +use crate::{ + error::DidPeerError, + peer_did::{ + numalgos::{ + numalgo2::resolve::resolve_numalgo2, numalgo3::Numalgo3, Numalgo, ResolvableNumalgo, + }, + FromDidDoc, PeerDid, + }, + resolver::options::PublicKeyEncoding, +}; + +mod encoding; +mod purpose; +pub mod resolve; +mod service_abbreviated; +mod verification_method; + +impl FromDidDoc for Numalgo2 { + fn from_did_doc( + did_document: DidDocument, + ) -> Result, DidPeerError> { + let mut did = String::from("did:peer:2"); + did = append_encoded_key_segments(did, &did_document)?; + did = append_encoded_service_segment(did, &did_document)?; + PeerDid::::parse(did) + } +} + +impl PeerDid { + pub fn to_numalgo3(&self) -> Result, DidPeerError> { + let numalgoless_id = self.did().id().chars().skip(2).collect::(); + let numalgoless_id_hashed = digest(numalgoless_id); + PeerDid::::parse(format!("did:peer:3.{}", numalgoless_id_hashed)) + } +} + +#[derive(Clone, Copy, Default, Debug, PartialEq)] +pub struct Numalgo2; + +impl Numalgo for Numalgo2 { + const NUMALGO_CHAR: char = '2'; +} + +impl ResolvableNumalgo for Numalgo2 { + fn resolve( + &self, + did: &Did, + public_key_encoding: PublicKeyEncoding, + ) -> Result, DidPeerError> { + resolve_numalgo2(did, public_key_encoding).map(|builder| builder.build()) + } +} diff --git a/did_peer/src/numalgos/numalgo2/purpose.rs b/did_peer/src/peer_did/numalgos/numalgo2/purpose.rs similarity index 100% rename from did_peer/src/numalgos/numalgo2/purpose.rs rename to did_peer/src/peer_did/numalgos/numalgo2/purpose.rs diff --git a/did_peer/src/numalgos/numalgo2/resolve/helpers.rs b/did_peer/src/peer_did/numalgos/numalgo2/resolve/helpers.rs similarity index 99% rename from did_peer/src/numalgos/numalgo2/resolve/helpers.rs rename to did_peer/src/peer_did/numalgos/numalgo2/resolve/helpers.rs index 1ea38dc516..fdddb11082 100644 --- a/did_peer/src/numalgos/numalgo2/resolve/helpers.rs +++ b/did_peer/src/peer_did/numalgos/numalgo2/resolve/helpers.rs @@ -10,11 +10,11 @@ use public_key::Key; use crate::{ error::DidPeerError, - numalgos::numalgo2::{ + peer_did::numalgos::numalgo2::{ purpose::ElementPurpose, service_abbreviated::ServiceAbbreviated, verification_method::get_verification_methods_by_key, }, - peer_did_resolver::options::PublicKeyEncoding, + resolver::options::PublicKeyEncoding, }; pub fn process_elements( diff --git a/did_peer/src/numalgos/numalgo2/resolve/mod.rs b/did_peer/src/peer_did/numalgos/numalgo2/resolve/mod.rs similarity index 87% rename from did_peer/src/numalgos/numalgo2/resolve/mod.rs rename to did_peer/src/peer_did/numalgos/numalgo2/resolve/mod.rs index 76160e2f88..daea3c7a41 100644 --- a/did_peer/src/numalgos/numalgo2/resolve/mod.rs +++ b/did_peer/src/peer_did/numalgos/numalgo2/resolve/mod.rs @@ -5,7 +5,7 @@ use did_doc_sov::extra_fields::ExtraFieldsSov; use did_parser::Did; use self::helpers::process_elements; -use crate::{error::DidPeerError, peer_did_resolver::options::PublicKeyEncoding}; +use crate::{error::DidPeerError, resolver::options::PublicKeyEncoding}; pub fn resolve_numalgo2( did: &Did, diff --git a/did_peer/src/numalgos/numalgo2/service_abbreviated.rs b/did_peer/src/peer_did/numalgos/numalgo2/service_abbreviated.rs similarity index 100% rename from did_peer/src/numalgos/numalgo2/service_abbreviated.rs rename to did_peer/src/peer_did/numalgos/numalgo2/service_abbreviated.rs diff --git a/did_peer/src/numalgos/numalgo2/verification_method.rs b/did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs similarity index 86% rename from did_peer/src/numalgos/numalgo2/verification_method.rs rename to did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs index 4e98a74014..1efca5b3e1 100644 --- a/did_peer/src/numalgos/numalgo2/verification_method.rs +++ b/did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs @@ -4,7 +4,7 @@ use did_doc::schema::verification_method::{ use did_parser::{Did, DidUrl}; use public_key::{Key, KeyType}; -use crate::{error::DidPeerError, peer_did_resolver::options::PublicKeyEncoding}; +use crate::{error::DidPeerError, resolver::options::PublicKeyEncoding}; pub fn get_verification_methods_by_key( key: &Key, @@ -49,7 +49,7 @@ pub fn get_key_by_verification_method(vm: &VerificationMethod) -> Result { return Err(DidPeerError::UnsupportedVerificationMethodType( t.to_owned(), - )) + )); } }; Ok(Key::new(vm.public_key_field().key_decoded()?, key_type)?) @@ -118,7 +118,9 @@ fn to_did_url_reference(key: &Key) -> Result { #[cfg(test)] mod tests { - use super::*; + use did_doc::schema::verification_method::{VerificationMethod, VerificationMethodType}; + use did_parser::Did; + use public_key::Key; fn did() -> Did { "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.\ @@ -172,11 +174,18 @@ mod tests { mod get_verification_methods_by_key { use super::*; + use crate::{ + peer_did::numalgos::numalgo2::verification_method, resolver::options::PublicKeyEncoding, + }; // Multibase encoded keys are multicodec-prefixed by their encoding type ... fn test_get_verification_methods_by_key_multibase(key: &Key) { - let vms = - get_verification_methods_by_key(key, &did(), PublicKeyEncoding::Multibase).unwrap(); + let vms = verification_method::get_verification_methods_by_key( + key, + &did(), + PublicKeyEncoding::Multibase, + ) + .unwrap(); assert_eq!(vms.len(), 1); assert_eq!( vms[0].public_key_field().key_decoded().unwrap(), @@ -187,8 +196,12 @@ mod tests { // ... and base58 encoded keys are not fn test_get_verification_methods_by_key_base58(key: &Key) { - let vms = - get_verification_methods_by_key(key, &did(), PublicKeyEncoding::Base58).unwrap(); + let vms = verification_method::get_verification_methods_by_key( + key, + &did(), + PublicKeyEncoding::Base58, + ) + .unwrap(); assert_eq!(vms.len(), 1); assert_ne!( vms[0].public_key_field().key_decoded().unwrap(), @@ -230,11 +243,13 @@ mod tests { mod get_key_by_verification_method { use super::*; + use crate::peer_did::numalgos::numalgo2::verification_method; #[test] fn test_get_key_by_verification_method_0() { assert_eq!( - get_key_by_verification_method(&verification_method_0()).unwrap(), + verification_method::get_key_by_verification_method(&verification_method_0()) + .unwrap(), key_0() ); } @@ -242,7 +257,8 @@ mod tests { #[test] fn test_get_key_by_verification_method_1() { assert_eq!( - get_key_by_verification_method(&verification_method_1()).unwrap(), + verification_method::get_key_by_verification_method(&verification_method_1()) + .unwrap(), key_1() ); } @@ -250,7 +266,8 @@ mod tests { #[test] fn test_get_key_by_verification_method_2() { assert_eq!( - get_key_by_verification_method(&verification_method_2()).unwrap(), + verification_method::get_key_by_verification_method(&verification_method_2()) + .unwrap(), key_2() ); } diff --git a/did_peer/src/peer_did/numalgos/numalgo3.rs b/did_peer/src/peer_did/numalgos/numalgo3.rs deleted file mode 100644 index 3232dd327a..0000000000 --- a/did_peer/src/peer_did/numalgos/numalgo3.rs +++ /dev/null @@ -1,17 +0,0 @@ -use did_parser::Did; - -use super::traits::{Numalgo, ToNumalgo3}; -use crate::{error::DidPeerError, peer_did::PeerDid}; - -#[derive(Clone, Copy, Default, Debug, PartialEq)] -pub struct Numalgo3; - -impl Numalgo for Numalgo3 { - const NUMALGO_CHAR: char = '3'; -} - -impl ToNumalgo3 for Numalgo3 { - fn to_numalgo3(did: &Did) -> Result, DidPeerError> { - Ok(PeerDid::from_parts(did.to_owned(), Self)) - } -} diff --git a/did_peer/src/peer_did/numalgos/numalgo3/mod.rs b/did_peer/src/peer_did/numalgos/numalgo3/mod.rs new file mode 100644 index 0000000000..576838b30d --- /dev/null +++ b/did_peer/src/peer_did/numalgos/numalgo3/mod.rs @@ -0,0 +1,50 @@ +use did_doc::schema::did_doc::DidDocument; +use did_doc_sov::extra_fields::ExtraFieldsSov; + +use crate::{ + error::DidPeerError, + peer_did::{ + numalgos::{numalgo2::Numalgo2, Numalgo}, + FromDidDoc, PeerDid, + }, +}; + +#[derive(Clone, Copy, Default, Debug, PartialEq)] +pub struct Numalgo3; + +impl Numalgo for Numalgo3 { + const NUMALGO_CHAR: char = '3'; +} + +impl FromDidDoc for Numalgo3 { + fn from_did_doc( + did_document: DidDocument, + ) -> Result, DidPeerError> { + PeerDid::::from_did_doc(did_document)?.to_numalgo3() + } +} + +#[cfg(test)] +mod tests { + use crate::peer_did::{ + numalgos::{numalgo2::Numalgo2, numalgo3::Numalgo3}, + PeerDid, + }; + + #[test] + fn test_generate_numalgo3() { + let peer_did_2 = PeerDid::::parse("did:peer:2\ + .Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc\ + .Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V\ + .Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg\ + .SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0".to_string()).unwrap(); + assert_eq!( + PeerDid::::parse( + "did:peer:3.0e857e93798921e83cfc2ef8bee9cafc25f15f4c9c7bee5ed9a9c62b56a62cca" + .to_string() + ) + .unwrap(), + peer_did_2.to_numalgo3().unwrap() + ); + } +} diff --git a/did_peer/src/peer_did/numalgos/traits.rs b/did_peer/src/peer_did/numalgos/traits.rs index 67f988dd91..4aad8609c2 100644 --- a/did_peer/src/peer_did/numalgos/traits.rs +++ b/did_peer/src/peer_did/numalgos/traits.rs @@ -2,7 +2,6 @@ use did_doc::schema::did_doc::DidDocument; use did_doc_sov::extra_fields::ExtraFieldsSov; use did_parser::Did; -use super::numalgo3::Numalgo3; use crate::{ error::DidPeerError, peer_did::{parse::parse_numalgo, validate::validate, PeerDid}, @@ -34,7 +33,3 @@ pub trait ResolvableNumalgo: Numalgo { public_key_encoding: PublicKeyEncoding, ) -> Result, DidPeerError>; } - -pub trait ToNumalgo3: Numalgo { - fn to_numalgo3(did: &Did) -> Result, DidPeerError>; -} diff --git a/did_peer/src/peer_did/parse.rs b/did_peer/src/peer_did/parse.rs index a69a0ecd06..f105479c29 100644 --- a/did_peer/src/peer_did/parse.rs +++ b/did_peer/src/peer_did/parse.rs @@ -1,7 +1,6 @@ use did_parser::Did; -use super::numalgos::NumalgoKind; -use crate::error::DidPeerError; +use crate::{error::DidPeerError, peer_did::numalgos::kind::NumalgoKind}; pub fn parse_numalgo(did: &Did) -> Result { did.id() diff --git a/did_peer/src/peer_did/regex.rs b/did_peer/src/peer_did/regex.rs deleted file mode 100644 index ac92dd7074..0000000000 --- a/did_peer/src/peer_did/regex.rs +++ /dev/null @@ -1,14 +0,0 @@ -use once_cell::sync::Lazy; -use regex::Regex; - -static GROUP_NUMALGO_0_AND_1: &str = r"([01](z)([1-9a-km-zA-HJ-NP-Z]{5,200}))"; -static GROUP_NUMALGO_2: &str = - r"(2((.[AEVID](z)([1-9a-km-zA-HJ-NP-Z]{5,200}))+(.(S)[0-9a-zA-Z=]*)?))"; -static GROUP_NUMALGO_3: &str = r"(3\.[0-9a-fA-F]{64})"; - -pub static PEER_DID_REGEX: Lazy = Lazy::new(|| { - Regex::new(&format!( - r"^did:peer:({GROUP_NUMALGO_0_AND_1}|{GROUP_NUMALGO_2}|{GROUP_NUMALGO_3})$" - )) - .unwrap() -}); diff --git a/did_peer/src/peer_did/validate.rs b/did_peer/src/peer_did/validate.rs index 558bf287c4..6d80c22d61 100644 --- a/did_peer/src/peer_did/validate.rs +++ b/did_peer/src/peer_did/validate.rs @@ -1,13 +1,27 @@ use did_parser::Did; +use once_cell::sync::Lazy; +use regex::Regex; -use super::regex::PEER_DID_REGEX; use crate::error::DidPeerError; +static GROUP_NUMALGO_0_AND_1: &str = r"([01](z)([1-9a-km-zA-HJ-NP-Z]{5,200}))"; +static GROUP_NUMALGO_2: &str = + r"(2((.[AEVID](z)([1-9a-km-zA-HJ-NP-Z]{5,200}))+(.(S)[0-9a-zA-Z=]*)?))"; +static GROUP_NUMALGO_3: &str = r"(3\.[0-9a-fA-F]{64})"; + +pub static PEER_DID_REGEX: Lazy = Lazy::new(|| { + Regex::new(&format!( + r"^did:peer:({GROUP_NUMALGO_0_AND_1}|{GROUP_NUMALGO_2}|{GROUP_NUMALGO_3})$" + )) + .unwrap() +}); + pub fn validate(did: &Did) -> Result<(), DidPeerError> { if !PEER_DID_REGEX.is_match(did.did()) { Err(DidPeerError::DidValidationError(format!( - "Invalid did: {}", - did.did() + "Invalid did: {} because it's not matching peer did regex {}", + did.did(), + *PEER_DID_REGEX ))) } else { Ok(()) diff --git a/did_peer/src/peer_did_resolver/mod.rs b/did_peer/src/peer_did_resolver/mod.rs deleted file mode 100644 index 3210452b56..0000000000 --- a/did_peer/src/peer_did_resolver/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod options; -pub mod resolver; diff --git a/did_peer/src/peer_did_resolver/resolver.rs b/did_peer/src/resolver/mod.rs similarity index 84% rename from did_peer/src/peer_did_resolver/resolver.rs rename to did_peer/src/resolver/mod.rs index 859f104d31..17ee58c9aa 100644 --- a/did_peer/src/peer_did_resolver/resolver.rs +++ b/did_peer/src/resolver/mod.rs @@ -9,11 +9,14 @@ use did_resolver::{ }, }; -use super::options::ExtraFieldsOptions; use crate::{ - error::DidPeerError, numalgos::numalgo2::resolve_numalgo2, peer_did::generic::GenericPeerDid, + error::DidPeerError, + peer_did::{generic::AnyPeerDid, numalgos::numalgo2::resolve::resolve_numalgo2}, + resolver::options::ExtraFieldsOptions, }; +pub mod options; + pub struct PeerDidResolver; #[async_trait] @@ -26,9 +29,9 @@ impl DidResolvable for PeerDidResolver { did: &Did, options: &DidResolutionOptions, ) -> Result, GenericError> { - let peer_did = GenericPeerDid::parse(did.to_owned())?; + let peer_did = AnyPeerDid::parse(did.to_owned())?; match peer_did { - GenericPeerDid::Numalgo2(peer_did) => { + AnyPeerDid::Numalgo2(peer_did) => { let did_doc = resolve_numalgo2(peer_did.did(), options.extra().public_key_encoding())? .add_also_known_as(peer_did.to_numalgo3()?.to_string().parse()?) diff --git a/did_peer/src/peer_did_resolver/options.rs b/did_peer/src/resolver/options.rs similarity index 100% rename from did_peer/src/peer_did_resolver/options.rs rename to did_peer/src/resolver/options.rs diff --git a/did_peer/tests/demo.rs b/did_peer/tests/demo.rs new file mode 100644 index 0000000000..fccd47d863 --- /dev/null +++ b/did_peer/tests/demo.rs @@ -0,0 +1,56 @@ +use std::error::Error; + +use did_doc::schema::{ + did_doc::DidDocument, + service::ServiceBuilder, + types::{uri::Uri, url::Url}, + verification_method::{VerificationMethod, VerificationMethodType}, +}; +use did_doc_sov::extra_fields::{didcommv1::ExtraFieldsDidCommV1, ExtraFieldsSov, KeyKind}; +use did_parser::{Did, DidUrl}; +use did_peer::peer_did::{ + numalgos::{numalgo2::Numalgo2, numalgo3::Numalgo3}, + PeerDid, +}; + +#[test] +fn demo() -> Result<(), Box> { + let recipient_key = KeyKind::Value("foo".to_string()); + let sov_service_extra = ExtraFieldsSov::DIDCommV1( + ExtraFieldsDidCommV1::builder() + .set_recipient_keys(vec![recipient_key]) + .build(), + ); + let service = ServiceBuilder::::new( + Uri::new("xyz://example.org")?, + Url::new("http://example.org")?, + sov_service_extra, + ) + .add_service_type("DIDCommMessaging".to_string())? + .build(); + + 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 ddo = DidDocument::builder(did) + .add_verification_method(verification_method) + .add_service(service) + .build(); + println!("diddoc: {}", ddo); + + let peer_did_2 = PeerDid::::from_did_doc(ddo.clone())?; + println!("PeerDid numalgo(2): {}", peer_did_2); + let peer_did_3 = PeerDid::::from_did_doc(ddo)?; + println!("PeerDid numalgo(3): {}", peer_did_3); + let peer_did_3_v2 = peer_did_2.to_numalgo3()?; + println!("Converted PeerDid numalgo(3): {}", peer_did_3_v2); + + Ok(()) +} diff --git a/did_peer/tests/generate.rs b/did_peer/tests/generate.rs index 0bba70998a..dc154045c1 100644 --- a/did_peer/tests/generate.rs +++ b/did_peer/tests/generate.rs @@ -3,7 +3,6 @@ mod fixtures; use did_doc::schema::did_doc::DidDocument; use did_doc_sov::extra_fields::ExtraFieldsSov; use did_peer::peer_did::{ - generate::{generate_numalgo2, generate_numalgo3}, numalgos::{numalgo2::Numalgo2, numalgo3::Numalgo3}, PeerDid, }; @@ -31,7 +30,7 @@ macro_rules! generate_test_numalgo2 { serde_json::from_str::>($did_doc).unwrap(); assert_eq!( PeerDid::::parse($peer_did.to_string()).unwrap(), - generate_numalgo2(did_document).unwrap() + PeerDid::::from_did_doc(did_document).unwrap() ); } }; @@ -45,7 +44,7 @@ macro_rules! generate_test_numalgo3 { serde_json::from_str::>($did_doc).unwrap(); assert_eq!( PeerDid::::parse($peer_did.to_string()).unwrap(), - generate_numalgo3(did_document).unwrap() + PeerDid::::from_did_doc(did_document).unwrap() ); } }; diff --git a/did_peer/tests/resolve_negative.rs b/did_peer/tests/resolve_negative.rs index 3d9ee81fae..64fca4925c 100644 --- a/did_peer/tests/resolve_negative.rs +++ b/did_peer/tests/resolve_negative.rs @@ -2,9 +2,9 @@ mod fixtures; use did_peer::{ error::DidPeerError, - peer_did_resolver::{ + resolver::{ options::{ExtraFieldsOptions, PublicKeyEncoding}, - resolver::PeerDidResolver, + PeerDidResolver, }, }; use did_resolver::traits::resolvable::{resolution_options::DidResolutionOptions, DidResolvable}; diff --git a/did_peer/tests/resolve_positive.rs b/did_peer/tests/resolve_positive.rs index f7e0ce57c6..cff56f3fd6 100644 --- a/did_peer/tests/resolve_positive.rs +++ b/did_peer/tests/resolve_positive.rs @@ -2,9 +2,9 @@ mod fixtures; use did_doc::schema::did_doc::DidDocument; use did_doc_sov::extra_fields::ExtraFieldsSov; -use did_peer::peer_did_resolver::{ +use did_peer::resolver::{ options::{ExtraFieldsOptions, PublicKeyEncoding}, - resolver::PeerDidResolver, + PeerDidResolver, }; use did_resolver::traits::resolvable::{resolution_options::DidResolutionOptions, DidResolvable}; use tokio::test; diff --git a/tools/display_as_json/Cargo.toml b/tools/display_as_json/Cargo.toml new file mode 100644 index 0000000000..56f9ed7721 --- /dev/null +++ b/tools/display_as_json/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "display_as_json" +version = "0.1.0" +edition = "2018" +authors = ["Your Name "] +description = "A custom derive macro to implement Display trait as JSON serialization" +license = "MIT" + +[lib] +proc-macro = true + +[dependencies] +syn = "1.0" +quote = "1.0" + +[dev-dependencies] +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" diff --git a/tools/display_as_json/src/lib.rs b/tools/display_as_json/src/lib.rs new file mode 100644 index 0000000000..10898935c1 --- /dev/null +++ b/tools/display_as_json/src/lib.rs @@ -0,0 +1,25 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::quote; + +#[proc_macro_derive(Display)] +pub fn display_as_json_derive(input: TokenStream) -> TokenStream { + let ast = syn::parse(input).unwrap(); + impl_display(&ast) +} + +fn impl_display(ast: &syn::DeriveInput) -> TokenStream { + let name = &ast.ident; + let gen = quote! { + impl std::fmt::Display for #name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let json = serde_json::to_string(self).unwrap_or_else(|e| { + format!("Error serializing {}: {}", stringify!(#name), e) + }); + write!(f, "{}", json) + } + } + }; + gen.into() +} diff --git a/tools/display_as_json/tests/demo.rs b/tools/display_as_json/tests/demo.rs new file mode 100644 index 0000000000..7737f565cc --- /dev/null +++ b/tools/display_as_json/tests/demo.rs @@ -0,0 +1,23 @@ +extern crate display_as_json; +extern crate serde; + +use serde_derive::{Deserialize, Serialize}; + +use crate::display_as_json::Display; + +#[derive(Serialize, Deserialize, Display)] +struct TestStruct { + field1: u32, + field2: String, +} + +#[test] +fn test_display_as_json() { + let instance = TestStruct { + field1: 42, + field2: "hello".to_string(), + }; + let displayed = format!("{}", instance); + let expected = r#"{"field1":42,"field2":"hello"}"#; + assert_eq!(displayed, expected); +}