From 4e65aec00edca46fb3738a827fedc430c6f24753 Mon Sep 17 00:00:00 2001 From: nain-F49FF806 <126972030+nain-F49FF806@users.noreply.github.com> Date: Tue, 31 Oct 2023 18:07:40 +0100 Subject: [PATCH 1/4] refactor: remove client-webapi (#1041) Signed-off-by: Naian <126972030+nain-F49FF806@users.noreply.github.com> --- Cargo.lock | 16 --------- Cargo.toml | 1 - agents/rust/mediator/client-tui/Cargo.toml | 2 +- agents/rust/mediator/client-tui/src/lib.rs | 25 +++++++++++++ agents/rust/mediator/client-tui/src/main.rs | 3 +- agents/rust/mediator/client-tui/src/tui.rs | 7 ++-- agents/rust/mediator/client-webapi/Cargo.toml | 20 ----------- agents/rust/mediator/client-webapi/README.md | 9 ----- .../mediator/client-webapi/src/http_routes.rs | 35 ------------------- agents/rust/mediator/client-webapi/src/lib.rs | 1 - .../rust/mediator/client-webapi/src/main.rs | 32 ----------------- 11 files changed, 31 insertions(+), 120 deletions(-) create mode 100644 agents/rust/mediator/client-tui/src/lib.rs delete mode 100644 agents/rust/mediator/client-webapi/Cargo.toml delete mode 100644 agents/rust/mediator/client-webapi/README.md delete mode 100644 agents/rust/mediator/client-webapi/src/http_routes.rs delete mode 100644 agents/rust/mediator/client-webapi/src/lib.rs delete mode 100644 agents/rust/mediator/client-webapi/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 0c0652d2d6..169261f074 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -937,31 +937,15 @@ version = "0.1.1" dependencies = [ "aries_vcx_core", "axum", - "client-webapi", "cursive", "futures", "log", "mediation", "mediator", "messages", - "serde_json", - "tokio", -] - -[[package]] -name = "client-webapi" -version = "0.1.1" -dependencies = [ - "aries_vcx_core", - "axum", - "log", - "mediation", - "mediator", - "messages", "reqwest", "serde_json", "tokio", - "tower-http", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 711a52a859..72d5ba16b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ members = [ "shared_vcx", "diddoc_legacy", "agents/rust/mediator", - "agents/rust/mediator/client-webapi", "agents/rust/mediator/client-tui", "agents/rust/aries-vcx-agent", "wrappers/vcx-napi-rs", diff --git a/agents/rust/mediator/client-tui/Cargo.toml b/agents/rust/mediator/client-tui/Cargo.toml index e5f8e3585b..10dbbac948 100644 --- a/agents/rust/mediator/client-tui/Cargo.toml +++ b/agents/rust/mediator/client-tui/Cargo.toml @@ -10,13 +10,13 @@ aries_vcx_core = { path = "../../../../aries_vcx_core", features = [ "vdrtools_wallet", ] } axum = "0.6.20" -client-webapi = { path = "../client-webapi" } cursive = { version = "0.20.0", features = ["crossterm-backend"] } futures = "0.3.28" log = "0.4.20" mediation = { path = "../mediation" } mediator = { path = ".." } messages = { path = "../../../../messages" } +reqwest = "0.11.22" serde_json = "1.0.107" tokio = { version = "1", features = ["rt-multi-thread", "macros"] } diff --git a/agents/rust/mediator/client-tui/src/lib.rs b/agents/rust/mediator/client-tui/src/lib.rs new file mode 100644 index 0000000000..318593c678 --- /dev/null +++ b/agents/rust/mediator/client-tui/src/lib.rs @@ -0,0 +1,25 @@ +use std::collections::VecDeque; + +use aries_vcx_core::wallet::base_wallet::BaseWallet; +use mediation::storage::MediatorPersistence; +use mediator::aries_agent::{transports::AriesReqwest, ArcAgent}; +use messages::msg_fields::protocols::out_of_band::invitation::Invitation as OOBInvitation; +use serde_json::{json, Value}; + +pub async fn handle_register( + agent: ArcAgent, + oob_invite: OOBInvitation, +) -> Result { + let mut aries_transport = AriesReqwest { + response_queue: VecDeque::new(), + client: reqwest::Client::new(), + }; + let state = agent + .establish_connection(oob_invite, &mut aries_transport) + .await + .map_err(|err| format!("{err:?}"))?; + Ok(json!({ + "status": "success", + "connection_completed": state + })) +} diff --git a/agents/rust/mediator/client-tui/src/main.rs b/agents/rust/mediator/client-tui/src/main.rs index 5cba16f032..fac5be2809 100644 --- a/agents/rust/mediator/client-tui/src/main.rs +++ b/agents/rust/mediator/client-tui/src/main.rs @@ -1,5 +1,6 @@ -/// Aries Agent TUI mod tui; + +/// Aries Agent TUI #[tokio::main] async fn main() { use mediator::{ diff --git a/agents/rust/mediator/client-tui/src/tui.rs b/agents/rust/mediator/client-tui/src/tui.rs index 59f0a8e1a7..db9459aa85 100644 --- a/agents/rust/mediator/client-tui/src/tui.rs +++ b/agents/rust/mediator/client-tui/src/tui.rs @@ -1,8 +1,7 @@ use std::sync::Arc; use aries_vcx_core::wallet::base_wallet::BaseWallet; -use axum::{extract::State, Json}; -use client_webapi::http_routes::handle_register; +use client_tui::handle_register; use cursive::{ direction::Orientation, event::Key, @@ -103,8 +102,8 @@ pub fn client_register_connect_cb> = s.user_data().expect("Userdata should contain Agent"); output.set_content(format!("{:#?}", oob_invite)); - match block_on(handle_register(State(agent.to_owned()), Json(oob_invite))) { - Ok(Json(res_json)) => output.set_content(serde_json::to_string_pretty(&res_json).unwrap()), + match block_on(handle_register(agent.to_owned(), oob_invite)) { + Ok(res_json) => output.set_content(serde_json::to_string_pretty(&res_json).unwrap()), Err(err) => output.set_content(err), }; } diff --git a/agents/rust/mediator/client-webapi/Cargo.toml b/agents/rust/mediator/client-webapi/Cargo.toml deleted file mode 100644 index 7b4ec25f67..0000000000 --- a/agents/rust/mediator/client-webapi/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "client-webapi" -version = "0.1.1" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -aries_vcx_core = { path = "../../../../aries_vcx_core", features = [ - "vdrtools_wallet", -] } -axum = "0.6.20" -log = "0.4.20" -mediation = { path = "../mediation" } -mediator = { version = "0.1.1", path = ".." } -messages = { path = "../../../../messages" } -reqwest = "0.11.22" -serde_json = "1.0.107" -tokio = { version = "1", features = ["rt-multi-thread", "macros"] } -tower-http = { version = "0.4.4", features = ["catch-panic"] } diff --git a/agents/rust/mediator/client-webapi/README.md b/agents/rust/mediator/client-webapi/README.md deleted file mode 100644 index 5bf4dcaa01..0000000000 --- a/agents/rust/mediator/client-webapi/README.md +++ /dev/null @@ -1,9 +0,0 @@ - -### Client API - -```yaml -`/client/register-using-oob`: -- **Input**: Json body containing OOB invite to connect to. -- **Description** : Attempts to connect to the Aries service defined in the OOB invite using DIDCOMM channel. - -``` diff --git a/agents/rust/mediator/client-webapi/src/http_routes.rs b/agents/rust/mediator/client-webapi/src/http_routes.rs deleted file mode 100644 index 04b8f40b0a..0000000000 --- a/agents/rust/mediator/client-webapi/src/http_routes.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::{collections::VecDeque, sync::Arc}; - -use aries_vcx_core::wallet::base_wallet::BaseWallet; -use axum::{extract::State, routing::post, Json, Router}; -use mediation::storage::MediatorPersistence; -use mediator::aries_agent::{transports::AriesReqwest, Agent, ArcAgent}; -use messages::msg_fields::protocols::out_of_band::invitation::Invitation as OOBInvitation; -use serde_json::{json, Value}; - -pub async fn handle_register( - State(agent): State>, - Json(oob_invite): Json, -) -> Result, String> { - let mut aries_transport = AriesReqwest { - response_queue: VecDeque::new(), - client: reqwest::Client::new(), - }; - let state = agent - .establish_connection(oob_invite, &mut aries_transport) - .await - .map_err(|err| format!("{err:?}"))?; - Ok(Json(json!({ - "status": "success", - "connection_completed": state - }))) -} - -pub async fn build_client_router( - agent: Agent, -) -> Router { - Router::default() - .route("/client/register-using-oob", post(handle_register)) - .layer(tower_http::catch_panic::CatchPanicLayer::new()) - .with_state(Arc::new(agent)) -} diff --git a/agents/rust/mediator/client-webapi/src/lib.rs b/agents/rust/mediator/client-webapi/src/lib.rs deleted file mode 100644 index 5db9fa2065..0000000000 --- a/agents/rust/mediator/client-webapi/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod http_routes; diff --git a/agents/rust/mediator/client-webapi/src/main.rs b/agents/rust/mediator/client-webapi/src/main.rs deleted file mode 100644 index 39ca0208f7..0000000000 --- a/agents/rust/mediator/client-webapi/src/main.rs +++ /dev/null @@ -1,32 +0,0 @@ -/// Client-side focused api accessible Aries Agent -#[tokio::main] -async fn main() { - use client_webapi::http_routes::build_client_router; - use mediator::{ - aries_agent::AgentBuilder, - utils::binary_utils::{load_dot_env, setup_logging}, - }; - - load_dot_env(); - setup_logging(); - log::info!("Putting up local web interface controlling client"); - let endpoint_root = std::env::var("ENDPOINT_ROOT").unwrap_or("127.0.0.1:3003".into()); - log::info!("Client web endpoint root address {}", endpoint_root); - let agent = AgentBuilder::new_demo_agent().await.unwrap(); - let app_router = build_client_router(agent).await; - axum::Server::bind( - &endpoint_root - .parse() - .expect("Pass an address to listen on like IP:PORT"), - ) - .serve(app_router.into_make_service()) - .await - .unwrap(); -} - -// fn main() { -// print!( -// "This is a placeholder binary. Please enable \"client_tui\" feature to to build the \ -// functional client_tui binary." -// ) -// } From 88f6e8e378865107aa32a30d80ba64dca64064bc Mon Sep 17 00:00:00 2001 From: Patrik Date: Wed, 1 Nov 2023 16:47:49 +0100 Subject: [PATCH 2/4] Did peer refactoring, new display macro (#1034) * Did peer refactoring, add examples, new display macro (#1034) Signed-off-by: Patrik Stas --- .github/workflows/main.yml | 4 +- Cargo.lock | 13 ++++ Cargo.toml | 3 +- did_doc/src/schema/did_doc.rs | 5 +- did_doc_sov/Cargo.toml | 1 + did_doc_sov/src/extra_fields/aip1.rs | 3 +- did_doc_sov/src/extra_fields/didcommv1.rs | 3 +- did_doc_sov/src/extra_fields/didcommv2.rs | 3 +- did_doc_sov/src/extra_fields/legacy.rs | 3 +- did_doc_sov/src/extra_fields/mod.rs | 2 +- did_doc_sov/src/lib.rs | 2 + did_peer/Cargo.toml | 1 + did_peer/README.md | 31 ++++++++ did_peer/examples/demo.rs | 69 +++++++++++++++++ did_peer/src/error.rs | 2 +- did_peer/src/lib.rs | 5 +- did_peer/src/numalgos/mod.rs | 2 - .../src/numalgos/numalgo2/generate/mod.rs | 21 ----- did_peer/src/numalgos/numalgo2/mod.rs | 8 -- did_peer/src/numalgos/numalgo3/generate.rs | 35 --------- did_peer/src/numalgos/numalgo3/mod.rs | 3 - did_peer/src/peer_did/generate.rs | 23 ------ did_peer/src/peer_did/generic.rs | 42 +++++----- did_peer/src/peer_did/mod.rs | 36 +++++---- did_peer/src/peer_did/numalgos/kind.rs | 47 ++++++++++++ did_peer/src/peer_did/numalgos/mod.rs | 76 ++++++++----------- .../numalgos/{numalgo0.rs => numalgo0/mod.rs} | 2 +- .../numalgos/{numalgo1.rs => numalgo1/mod.rs} | 2 +- did_peer/src/peer_did/numalgos/numalgo2.rs | 37 --------- .../numalgos/numalgo2/encoding.rs} | 2 +- .../src/peer_did/numalgos/numalgo2/mod.rs | 58 ++++++++++++++ .../numalgos/numalgo2/purpose.rs | 0 .../numalgos/numalgo2/resolve/helpers.rs | 4 +- .../numalgos/numalgo2/resolve/mod.rs | 2 +- .../numalgos/numalgo2/service_abbreviated.rs | 0 .../numalgos/numalgo2/verification_method.rs | 37 ++++++--- did_peer/src/peer_did/numalgos/numalgo3.rs | 17 ----- .../src/peer_did/numalgos/numalgo3/mod.rs | 50 ++++++++++++ did_peer/src/peer_did/numalgos/traits.rs | 5 -- did_peer/src/peer_did/parse.rs | 3 +- did_peer/src/peer_did/regex.rs | 14 ---- did_peer/src/peer_did/validate.rs | 20 ++++- did_peer/src/peer_did_resolver/mod.rs | 2 - .../resolver.rs => resolver/mod.rs} | 11 ++- .../options.rs | 0 did_peer/tests/demo.rs | 56 ++++++++++++++ did_peer/tests/generate.rs | 5 +- did_peer/tests/resolve_negative.rs | 4 +- did_peer/tests/resolve_positive.rs | 4 +- tools/display_as_json/Cargo.toml | 19 +++++ tools/display_as_json/src/lib.rs | 25 ++++++ tools/display_as_json/tests/demo.rs | 23 ++++++ 52 files changed, 548 insertions(+), 297 deletions(-) create mode 100644 did_peer/README.md create mode 100644 did_peer/examples/demo.rs delete mode 100644 did_peer/src/numalgos/mod.rs delete mode 100644 did_peer/src/numalgos/numalgo2/generate/mod.rs delete mode 100644 did_peer/src/numalgos/numalgo2/mod.rs delete mode 100644 did_peer/src/numalgos/numalgo3/generate.rs delete mode 100644 did_peer/src/numalgos/numalgo3/mod.rs delete mode 100644 did_peer/src/peer_did/generate.rs create mode 100644 did_peer/src/peer_did/numalgos/kind.rs rename did_peer/src/peer_did/numalgos/{numalgo0.rs => numalgo0/mod.rs} (77%) rename did_peer/src/peer_did/numalgos/{numalgo1.rs => numalgo1/mod.rs} (77%) delete mode 100644 did_peer/src/peer_did/numalgos/numalgo2.rs rename did_peer/src/{numalgos/numalgo2/generate/helpers.rs => peer_did/numalgos/numalgo2/encoding.rs} (99%) create mode 100644 did_peer/src/peer_did/numalgos/numalgo2/mod.rs rename did_peer/src/{ => peer_did}/numalgos/numalgo2/purpose.rs (100%) rename did_peer/src/{ => peer_did}/numalgos/numalgo2/resolve/helpers.rs (99%) rename did_peer/src/{ => peer_did}/numalgos/numalgo2/resolve/mod.rs (87%) rename did_peer/src/{ => peer_did}/numalgos/numalgo2/service_abbreviated.rs (100%) rename did_peer/src/{ => peer_did}/numalgos/numalgo2/verification_method.rs (86%) delete mode 100644 did_peer/src/peer_did/numalgos/numalgo3.rs create mode 100644 did_peer/src/peer_did/numalgos/numalgo3/mod.rs delete mode 100644 did_peer/src/peer_did/regex.rs delete mode 100644 did_peer/src/peer_did_resolver/mod.rs rename did_peer/src/{peer_did_resolver/resolver.rs => resolver/mod.rs} (84%) rename did_peer/src/{peer_did_resolver => resolver}/options.rs (100%) create mode 100644 did_peer/tests/demo.rs create mode 100644 tools/display_as_json/Cargo.toml create mode 100644 tools/display_as_json/src/lib.rs create mode 100644 tools/display_as_json/tests/demo.rs 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); +} From ad26ecfb94514aa1901d28821ac6c79adf7037ed Mon Sep 17 00:00:00 2001 From: nain-F49FF806 <126972030+nain-F49FF806@users.noreply.github.com> Date: Thu, 2 Nov 2023 10:10:38 +0100 Subject: [PATCH 3/4] feat(mediator): support for pickup protocol processing (#1029) feat(mediator): support for pickup protocol processing (#1029) Signed-off-by: Naian <126972030+nain-F49FF806@users.noreply.github.com> --- Cargo.lock | 15 +- agents/rust/mediator/Cargo.toml | 1 + agents/rust/mediator/mediation/Cargo.toml | 7 +- agents/rust/mediator/mediation/README.md | 49 +--- .../mediator/mediation/src/didcomm_types.rs | 90 ------ agents/rust/mediator/mediation/src/router.rs | 7 +- .../mediator/mediation/src/routes/pickup.rs | 118 ++++---- agents/rust/mediator/src/aries_agent/mod.rs | 9 +- .../rust/mediator/src/didcomm_handlers/mod.rs | 23 +- .../mediator/src/didcomm_handlers/pickup.rs | 18 +- agents/rust/mediator/src/http_routes/mod.rs | 4 +- .../tests/mediator-protocol-pickup.rs | 263 ++++++++++++++++++ .../src/msg_fields/protocols/pickup/mod.rs | 2 +- 13 files changed, 393 insertions(+), 213 deletions(-) create mode 100644 agents/rust/mediator/tests/mediator-protocol-pickup.rs diff --git a/Cargo.lock b/Cargo.lock index ddc8d0e4e8..db611986f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -711,6 +711,15 @@ version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +[[package]] +name = "base64-url" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c5b0a88aa36e9f095ee2e2b13fb8c5e4313e022783aedacc123328c0084916d" +dependencies = [ + "base64", +] + [[package]] name = "base64ct" version = "1.6.0" @@ -2873,21 +2882,24 @@ dependencies = [ [[package]] name = "mediation" -version = "0.2.3" +version = "0.2.4" dependencies = [ "async-trait", "axum", "axum-macros", + "base64-url", "dotenvy", "env_logger 0.10.0", "futures", "log", + "messages", "reqwest", "serde", "serde_json", "serde_with", "sqlx", "tokio", + "uuid 1.5.0", ] [[package]] @@ -2900,6 +2912,7 @@ dependencies = [ "async-trait", "axum", "axum-macros", + "base64-url", "chrono", "diddoc_legacy", "dotenvy", diff --git a/agents/rust/mediator/Cargo.toml b/agents/rust/mediator/Cargo.toml index 01f61b0759..ad5ee75aa6 100644 --- a/agents/rust/mediator/Cargo.toml +++ b/agents/rust/mediator/Cargo.toml @@ -38,5 +38,6 @@ mediation = { path = "./mediation" } test_utils = { path = "../../../tools/test_utils" } [dev-dependencies] +base64-url = "2.0.0" chrono = "0.4.31" reqwest = { version = "0.11.20", features = ["blocking"] } diff --git a/agents/rust/mediator/mediation/Cargo.toml b/agents/rust/mediator/mediation/Cargo.toml index b8bdb6c90a..7a3598d838 100644 --- a/agents/rust/mediator/mediation/Cargo.toml +++ b/agents/rust/mediator/mediation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mediation" -version = "0.2.3" +version = "0.2.4" edition = "2021" [lib] @@ -10,23 +10,26 @@ path = "src/lib.rs" [features] default = ["mysql_db", "mediator_persistence_extras"] # postgres_db=["sqlx/postgres"] -mysql_db=["sqlx/mysql"] +mysql_db = ["sqlx/mysql"] # any_db=["sqlx/all-databases"] mediator_persistence_extras = [] [dependencies] async-trait = "0.1.72" axum = "0.6.18" +base64-url = "2.0.0" dotenvy = "0.15.7" env_logger = "0.10.0" futures = "0.3.28" log = "0.4.19" +messages = { path = "../../../../messages" } serde = { version = "1.0.164", features = ["derive"] } serde_json = "1.0.104" serde_with = { version = "3.1.0", features = ["base64"] } sqlx = { version = "0.7", features = ["runtime-tokio"], optional = true } # sqlx = { version = "0.5.8", git = "https://github.com/jovfer/sqlx", branch = "feature/json_no_preserve_order_v5", features = [ "sqlite", "mysql", "json_no_preserve_order", "runtime-tokio-rustls"], optional = true } tokio = { version = "1.28.2", features = ["rt-multi-thread", "macros"] } +uuid = { version = "1.5.0", features = ["v4"] } # Workaround required because of bug in sqlx pre v6 https://github.com/launchbadge/sqlx/issues/2418 # [build-dependencies] diff --git a/agents/rust/mediator/mediation/README.md b/agents/rust/mediator/mediation/README.md index 0f612cfee6..b5c05e2340 100644 --- a/agents/rust/mediator/mediation/README.md +++ b/agents/rust/mediator/mediation/README.md @@ -1,48 +1,5 @@ -> 🚧🚧**WIP**🚧🚧: Integration into aries-vcx in process. See main branch for the MVP http service. +# Aries mediator mediation -# Aries mediator service (http) +## Mediator service business logic -## History - -This repo was intended to be a test project to try Rust and Axum features. - -Over time it has turned into a ~fully functional aries mediator service supporting the following Aries concepts over ***http*** endpoints. - -> **Caveat**: Authentication must be handled at another layer. Integration with [aries-vcx] is intended to enable this. - -- [Mediator coordination protocol](https://github.com/hyperledger/aries-rfcs/blob/main/features/0211-route-coordination/README.md) -- [Core:Routing: Forward Message](https://github.com/hyperledger/aries-rfcs/blob/main/concepts/0094-cross-domain-messaging/README.md#corerouting10forward) -- [Pickup protocol 2.0](https://github.com/hyperledger/aries-rfcs/tree/main/features/0685-pickup-v2) - -[aries-vcx]: https://github.com/hyperledger/aries-vcx - -Original readme is available below. - -> # axum-test-server -> -> A axum server app to test and learn Rust and Axum features. -> -> The commits are made in such a way as to demonstrate and try one feature or workflow (refactoring) at a time. -> So the git log could be educative. -> -> ## Some Interesting commits -> -> 1. [feat(main.rs): :thread: Demo server as in axum docs](https://github.com/nain-F49FF806/axum-test-server/commit/d7fceaf9b731251cdbe8642c716dfaa3a697349a) -> -> 2. [refactor: `use` too bring names into local namespace](https://github.com/nain-F49FF806/axum-test-server/commit/f3a58597fc05fe5353140e764d532446ff10000e) -> -> 3. [refactor: break off some code into module and load module in main](https://github.com/nain-F49FF806/axum-test-server/commit/253956dc30866f516f484c6ef549c55054cb9f3f) -> -> 4. [refactor: Use functions in sibling module by declaring their path from root crate](https://github.com/nain-F49FF806/axum-test-server/commit/f7a5020ba52876e463c86efb3390af527e09990c#r121244243) -> -> 5. [refactor: modules can have sub-modules, which can then be loaded by others using path from root crate (*if made public*)](https://github.com/nain-F49FF806/axum-test-server/commit/877cf3bac05d9cf786db3ae45202b2d4d9a98a5c) -> -> 6. [feat(json): serde macros help with serializing, deserializing from Rust structs to JSON wire format](https://github.com/nain-F49FF806/axum-test-server/commit/505ec1ec8fc6169620be235231643f678bab20ff) -> -> -> ## Notess -> -> You can also look at a blog post with some personal notes (mostly for the Rust side) here : [running-notes-on-rust-and-axum-framework] -> -> [running-notes-on-rust-and-axum-framework]: https://envs.net/~nain/aries-vcx-diaries/running-notes-on-rust-and-axum-framework-ft-tutorial-course-by-brooks-builds.html -> \ No newline at end of file +## Mediator Persistence diff --git a/agents/rust/mediator/mediation/src/didcomm_types.rs b/agents/rust/mediator/mediation/src/didcomm_types.rs index dbefaea9fa..627bfb38d9 100644 --- a/agents/rust/mediator/mediation/src/didcomm_types.rs +++ b/agents/rust/mediator/mediation/src/didcomm_types.rs @@ -1,17 +1,9 @@ // Copyright 2023 Naian G. // SPDX-License-Identifier: Apache-2.0 -pub use pickup_delivery_message_structs::*; use serde::{Deserialize, Serialize}; -use serde_with::skip_serializing_none; - pub mod type_uri { pub const FORWARD: &str = "https://didcomm.org/routing/1.0/forward"; - pub const PICKUP_STATUS_REQ: &str = "https://didcomm.org/messagepickup/2.0/status-request"; - pub const PICKUP_STATUS: &str = "https://didcomm.org/messagepickup/2.0/status"; - pub const PICKUP_DELIVERY_REQ: &str = "https://didcomm.org/messagepickup/2.0/delivery-request"; - pub const PICKUP_DELIVERY: &str = "https://didcomm.org/messagepickup/2.0/delivery"; - pub const PICKUP_RECEIVED: &str = "https://didcomm.org/messagepickup/2.0/messages-received"; } #[derive(Debug, Serialize, Deserialize, sqlx::FromRow)] @@ -34,86 +26,6 @@ impl ForwardMsg { } } -#[derive(Serialize, Deserialize, Debug)] -#[serde(tag = "@type")] -pub enum PickupMsgEnum { - #[serde(rename = "https://didcomm.org/messagepickup/2.0/status")] - PickupStatusMsg(PickupStatusMsg), - #[serde(rename = "https://didcomm.org/messagepickup/2.0/status-request")] - PickupStatusReqMsg(PickupStatusReqMsg), - #[serde(rename = "https://didcomm.org/messagepickup/2.0/delivery-request")] - PickupDeliveryReq(PickupDeliveryReqMsg), - #[serde(rename = "https://didcomm.org/messagepickup/2.0/delivery")] - PickupDelivery(PickupDeliveryMsg), - #[serde(rename = "https://didcomm.org/messagepickup/2.0/messages-received")] - MessageReceived(MessageReceivedMsg), - #[serde(rename = "https://didcomm.org/messagepickup/2.0/live-delivery-change")] - LiveDeliveryChange(LiveDeliveryChangeMsg), - #[serde(rename = "https://didcomm.org/notification/1.0/problem-report")] - ProblemReport(ProblemReportMsg), -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Debug)] -pub struct PickupStatusMsg { - pub message_count: u32, - pub recipient_key: Option, -} - -impl PickupStatusMsg { - pub fn new(message_count: u32, recipient_key: Option) -> PickupStatusMsg { - PickupStatusMsg { - message_count, - recipient_key, - } - } -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Debug)] -pub struct PickupStatusReqMsg { - #[serde(default)] - pub auth_pubkey: String, - pub recipient_key: Option, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Debug)] -pub struct PickupDeliveryReqMsg { - #[serde(default)] - pub auth_pubkey: String, - pub limit: u32, - pub recipient_key: Option, -} - -pub mod pickup_delivery_message_structs { - use serde_with::{base64::Base64, serde_as}; - - use super::{skip_serializing_none, Deserialize, Serialize}; - - #[serde_as] - #[derive(Serialize, Deserialize, Debug)] - pub struct PickupDeliveryMsgAttachData { - #[serde_as(as = "Base64")] - pub base64: Vec, - } - - #[derive(Serialize, Deserialize, Debug)] - pub struct PickupDeliveryMsgAttach { - pub id: String, - #[serde(rename = "data")] - pub data: PickupDeliveryMsgAttachData, - } - - #[skip_serializing_none] - #[derive(Serialize, Deserialize, Debug)] - pub struct PickupDeliveryMsg { - pub recipient_key: Option, - #[serde(rename = "~attach")] - pub attach: Vec, - } -} - #[derive(Serialize, Deserialize, Debug)] pub struct LiveDeliveryChangeMsg { pub live_delivery: bool, @@ -131,8 +43,6 @@ pub struct MessageReceivedMsg { pub mod mediator_coord_structs { use serde::{Deserialize, Serialize}; - // use serde_with::skip_serializing_none; - #[derive(Serialize, Deserialize, Debug)] #[serde(tag = "@type")] pub enum MediatorCoordMsgEnum { diff --git a/agents/rust/mediator/mediation/src/router.rs b/agents/rust/mediator/mediation/src/router.rs index 6377fc527b..1144a39040 100644 --- a/agents/rust/mediator/mediation/src/router.rs +++ b/agents/rust/mediator/mediation/src/router.rs @@ -9,10 +9,7 @@ use axum::{ }; use crate::{ - routes::{ - forward::handle_forward, hello_world, json, json::respond_message_json, - pickup::handle_pickup, - }, + routes::{forward::handle_forward, hello_world, json, json::respond_message_json}, storage, }; @@ -30,7 +27,7 @@ pub async fn create_router() -> Router { get(json::echo_message_json).post(respond_message_json), ) .route("/forward", post(handle_forward)) - .route("/pickup", post(handle_pickup)) + // .route("/pickup", post(handle_pickup)) // .route("/coord", post(handle_coord)) .with_state(Arc::new(storage)) } diff --git a/agents/rust/mediator/mediation/src/routes/pickup.rs b/agents/rust/mediator/mediation/src/routes/pickup.rs index 9e3a70c2bd..f918952345 100644 --- a/agents/rust/mediator/mediation/src/routes/pickup.rs +++ b/agents/rust/mediator/mediation/src/routes/pickup.rs @@ -4,66 +4,81 @@ use std::sync::Arc; use axum::{extract::State, http::StatusCode, Json}; use log::info; - -use crate::{ - didcomm_types::{ - pickup_delivery_message_structs::*, PickupDeliveryReqMsg, PickupMsgEnum, PickupStatusMsg, - PickupStatusReqMsg, ProblemReportMsg, +use messages::{ + decorators::attachment::{Attachment, AttachmentData, AttachmentType}, + msg_fields::protocols::pickup::{ + Delivery, DeliveryContent, DeliveryRequestContent, Pickup, Status, StatusContent, + StatusDecorators, StatusRequestContent, }, - storage::MediatorPersistence, }; +use uuid::Uuid; + +use crate::storage::MediatorPersistence; -pub async fn handle_pickup( +pub async fn handle_pickup_authenticated( State(storage): State>, - Json(pickup_message): Json, -) -> (StatusCode, Json) { + Json(pickup_message): Json, + auth_pubkey: &str, +) -> (StatusCode, Json) { match &pickup_message { - PickupMsgEnum::PickupStatusReqMsg(status_request) => ( + Pickup::StatusRequest(status_request) => ( StatusCode::OK, - handle_pickup_status_req(status_request, storage).await, + handle_pickup_status_req(&status_request.content, storage, auth_pubkey).await, ), // Why is client sending us status? That's server's job. - PickupMsgEnum::PickupStatusMsg(_status) => ( + Pickup::Status(_status) => ( StatusCode::BAD_REQUEST, - handle_pickup_type_not_implemented().await, + handle_pickup_default_status(storage, auth_pubkey).await, ), - PickupMsgEnum::PickupDeliveryReq(delivery_request) => { - handle_pickup_delivery_req(delivery_request, storage).await + Pickup::DeliveryRequest(delivery_request) => { + handle_pickup_delivery_req(&delivery_request.content, storage, auth_pubkey).await } _ => { info!("Received {:#?}", &pickup_message); ( StatusCode::NOT_IMPLEMENTED, - handle_pickup_type_not_implemented().await, + handle_pickup_default_status(storage, auth_pubkey).await, ) } } } async fn handle_pickup_status_req( - status_request: &PickupStatusReqMsg, + status_request: &StatusRequestContent, storage: Arc, -) -> Json { + auth_pubkey: &str, +) -> Json { info!("Received {:#?}", &status_request); - let auth_pubkey = &status_request.auth_pubkey; let message_count = storage .retrieve_pending_message_count(auth_pubkey, status_request.recipient_key.as_ref()) .await .unwrap(); - let status = PickupStatusMsg { - message_count, - recipient_key: status_request.recipient_key.to_owned(), + let status_content = if let Some(recipient_key) = status_request.recipient_key.clone() { + StatusContent::builder() + .message_count(message_count) + .recipient_key(recipient_key) + .build() + } else { + StatusContent::builder() + .message_count(message_count) + .build() }; + let status = Status::builder() + .content(status_content) + .decorators(StatusDecorators::default()) + .id(Uuid::new_v4().to_string()) + .build(); + info!("Sending {:#?}", &status); - Json(PickupMsgEnum::PickupStatusMsg(status)) + Json(Pickup::Status(status)) } async fn handle_pickup_delivery_req( - delivery_request: &PickupDeliveryReqMsg, + delivery_request: &DeliveryRequestContent, storage: Arc, -) -> (StatusCode, Json) { + auth_pubkey: &str, +) -> (StatusCode, Json) { info!("Received {:#?}", &delivery_request); - let auth_pubkey = &delivery_request.auth_pubkey; let messages = storage .retrieve_pending_messages( auth_pubkey, @@ -75,31 +90,37 @@ async fn handle_pickup_delivery_req( // for (message_id, message_content) in messages.into_iter() { // info!("Message {:#?} {:#?}", message_id, String::from_utf8(message_content).unwrap()) // } - let attach: Vec = messages + let attach: Vec = messages .into_iter() - .map(|(message_id, message_content)| PickupDeliveryMsgAttach { - id: message_id, - data: PickupDeliveryMsgAttachData { - base64: message_content, - }, + .map(|(message_id, message_content)| { + Attachment::builder() + .id(message_id) + .data( + AttachmentData::builder() + .content(AttachmentType::Base64(base64_url::encode(&message_content))) + .build(), + ) + .build() }) .collect(); if !attach.is_empty() { ( StatusCode::OK, - Json(PickupMsgEnum::PickupDelivery(PickupDeliveryMsg { - recipient_key: delivery_request.recipient_key.to_owned(), - attach, - })), + Json(Pickup::Delivery( + Delivery::builder() + .content(DeliveryContent { + recipient_key: delivery_request.recipient_key.to_owned(), + attach, + }) + .id(Uuid::new_v4().to_string()) + .build(), + )), ) } else { - // send status message instead + // send default status message instead ( StatusCode::OK, - Json(PickupMsgEnum::PickupStatusMsg(PickupStatusMsg { - message_count: 0, - recipient_key: delivery_request.recipient_key.to_owned(), - })), + handle_pickup_default_status(storage, auth_pubkey).await, ) } } @@ -119,11 +140,12 @@ async fn handle_pickup_delivery_req( // Json(PickupMsgEnum::PickupStatusMsg(status)) // } -async fn handle_pickup_type_not_implemented() -> Json { - let problem = ProblemReportMsg { - description: "This pickup request type not yet implemented.\n Please try again later" - .to_owned(), - }; - info!("Sending {:#?}", &problem); - Json(PickupMsgEnum::ProblemReport(problem)) +/// Return status by default +async fn handle_pickup_default_status( + storage: Arc, + auth_pubkey: &str, +) -> Json { + info!("Default behavior: responding with status"); + let status_request = StatusRequestContent::builder().build(); + handle_pickup_status_req(&status_request, storage, auth_pubkey).await } diff --git a/agents/rust/mediator/src/aries_agent/mod.rs b/agents/rust/mediator/src/aries_agent/mod.rs index 1713774c77..79f3bead2b 100644 --- a/agents/rust/mediator/src/aries_agent/mod.rs +++ b/agents/rust/mediator/src/aries_agent/mod.rs @@ -166,15 +166,16 @@ impl Agent { pub async fn auth_and_get_details( &self, sender_verkey: &Option, - ) -> Result<(String, VerKey, AriesDidDoc), String> { + ) -> Result<(String, VerKey, VerKey, AriesDidDoc), String> { let auth_pubkey = sender_verkey .as_deref() - .ok_or("Anonymous sender can't be authenticated")?; + .ok_or("Anonymous sender can't be authenticated")? + .to_owned(); let (_sr_no, account_name, our_signing_key, did_doc_json) = - self.persistence.get_account_details(auth_pubkey).await?; + self.persistence.get_account_details(&auth_pubkey).await?; let diddoc = serde_json::from_value::(did_doc_json).map_err(string_from_std_error)?; - Ok((account_name, our_signing_key, diddoc)) + Ok((account_name, auth_pubkey, our_signing_key, diddoc)) } pub async fn handle_connection_req( &self, diff --git a/agents/rust/mediator/src/didcomm_handlers/mod.rs b/agents/rust/mediator/src/didcomm_handlers/mod.rs index b178ce8878..f0e60f0296 100644 --- a/agents/rust/mediator/src/didcomm_handlers/mod.rs +++ b/agents/rust/mediator/src/didcomm_handlers/mod.rs @@ -21,7 +21,6 @@ use pickup::handle_pickup_protocol; #[serde(untagged)] enum GeneralAriesMessage { AriesVCXSupported(AriesMessage), - XumPickup(mediation::didcomm_types::PickupMsgEnum), XumCoord(mediation::didcomm_types::mediator_coord_structs::MediatorCoordMsgEnum), } pub fn unhandled_aries_message(message: impl Debug) -> String { @@ -35,7 +34,7 @@ pub async fn handle_aries( log::info!("processing message {:?}", &didcomm_msg); let unpacked = agent.unpack_didcomm(&didcomm_msg).await.unwrap(); let aries_message: GeneralAriesMessage = - serde_json::from_str(&unpacked.message).expect("Decoding unpacked message as AriesMessage"); + serde_json::from_str(&unpacked.message).map_err(|e| e.to_string())?; let packed_response = if let GeneralAriesMessage::AriesVCXSupported(AriesMessage::Connection(conn)) = aries_message @@ -47,13 +46,21 @@ pub async fn handle_aries( handle_routing_forward(agent.clone(), forward).await?; return Ok(Json(json!({}))); } else { - let (account_name, our_signing_key, their_diddoc) = + // Auth known VerKey then process account related messages + let (account_name, auth_pubkey, our_signing_key, their_diddoc) = agent.auth_and_get_details(&unpacked.sender_verkey).await?; - let auth_pubkey = unpacked - .sender_verkey - .expect("Sender key authenticated above, so it must be present.."); log::info!("Processing message for {:?}", account_name); match aries_message { + GeneralAriesMessage::AriesVCXSupported(AriesMessage::Pickup(pickup_message)) => { + let pickup_response = + handle_pickup_protocol(&agent, pickup_message, &auth_pubkey).await?; + let aries_response = AriesMessage::Pickup(pickup_response); + let aries_response_bytes = + serde_json::to_vec(&aries_response).map_err(string_from_std_error)?; + agent + .pack_didcomm(&aries_response_bytes, &our_signing_key, &their_diddoc) + .await? + } GeneralAriesMessage::AriesVCXSupported(aries_message) => { Err(unhandled_aries_message(aries_message))? } @@ -66,10 +73,6 @@ pub async fn handle_aries( .pack_didcomm(&aries_response, &our_signing_key, &their_diddoc) .await? } - GeneralAriesMessage::XumPickup(pickup_message) => { - handle_pickup_protocol(agent, pickup_message).await?; - todo!(); - } } }; let EncryptionEnvelope(packed_message_bytes) = packed_response; diff --git a/agents/rust/mediator/src/didcomm_handlers/pickup.rs b/agents/rust/mediator/src/didcomm_handlers/pickup.rs index 90f0ba6dae..1d7959cce7 100644 --- a/agents/rust/mediator/src/didcomm_handlers/pickup.rs +++ b/agents/rust/mediator/src/didcomm_handlers/pickup.rs @@ -1,10 +1,18 @@ -use mediation::didcomm_types::PickupMsgEnum; +use axum::{extract::State, Json}; +use messages::msg_fields::protocols::pickup::Pickup; use super::utils::prelude::*; pub async fn handle_pickup_protocol( - _agent: ArcAgent, - _pickup_msg: PickupMsgEnum, -) -> Result { - todo!() + agent: &ArcAgent, + pickup_message: Pickup, + auth_pubkey: &str, +) -> Result { + let (_, Json(pickup_response)) = mediation::routes::pickup::handle_pickup_authenticated( + State(agent.get_persistence_ref()), + Json(pickup_message), + auth_pubkey, + ) + .await; + Ok(pickup_response) } diff --git a/agents/rust/mediator/src/http_routes/mod.rs b/agents/rust/mediator/src/http_routes/mod.rs index 2c5c3d21a8..3998f64afa 100644 --- a/agents/rust/mediator/src/http_routes/mod.rs +++ b/agents/rust/mediator/src/http_routes/mod.rs @@ -58,7 +58,9 @@ pub async fn handle_didcomm( State(agent): State>, didcomm_msg: Bytes, ) -> Result, String> { - didcomm_handlers::handle_aries(State(agent), didcomm_msg).await + didcomm_handlers::handle_aries(State(agent), didcomm_msg) + .await + .map_err(|e| e.to_string()) } pub async fn readme() -> Html { diff --git a/agents/rust/mediator/tests/mediator-protocol-pickup.rs b/agents/rust/mediator/tests/mediator-protocol-pickup.rs new file mode 100644 index 0000000000..2084b64510 --- /dev/null +++ b/agents/rust/mediator/tests/mediator-protocol-pickup.rs @@ -0,0 +1,263 @@ +mod common; +use std::collections::VecDeque; + +use aries_vcx::utils::encryption_envelope::EncryptionEnvelope; +use aries_vcx_core::wallet::base_wallet::BaseWallet; +use diddoc_legacy::aries::diddoc::AriesDidDoc; +use mediation::{ + didcomm_types::mediator_coord_structs::{ + KeylistUpdateItem, KeylistUpdateItemAction, KeylistUpdateRequestData, MediateGrantData, + MediatorCoordMsgEnum, + }, + storage::MediatorPersistence, +}; +use mediator::{ + aries_agent::{ + transports::{AriesReqwest, AriesTransport}, + utils::oob2did, + Agent, + }, + utils::{structs::VerKey, GenericStringError}, +}; +use messages::{ + decorators::attachment::AttachmentType, + msg_fields::protocols::{ + basic_message::{BasicMessage, BasicMessageContent, BasicMessageDecorators}, + out_of_band::invitation::Invitation as OOBInvitation, + pickup::{ + DeliveryRequest, DeliveryRequestContent, DeliveryRequestDecorators, Pickup, + StatusRequest, StatusRequestContent, StatusRequestDecorators, + }, + }, + AriesMessage, +}; + +use crate::common::{ + agent_and_transport_utils::{ + gen_mediator_connected_agent, send_message_and_pop_response_message, + }, + prelude::*, + test_setup::setup_env_logging, +}; + +static LOGGING_INIT: std::sync::Once = std::sync::Once::new(); + +async fn get_mediator_grant_data( + agent: &Agent, + agent_aries_transport: &mut impl AriesTransport, + agent_verkey: &VerKey, + mediator_diddoc: &AriesDidDoc, +) -> MediateGrantData { + // prepare request message + let message = MediatorCoordMsgEnum::MediateRequest; + let message_bytes = serde_json::to_vec(&message).unwrap(); + // send message and get response + let response_message = send_message_and_pop_response_message( + &message_bytes, + agent, + agent_aries_transport, + agent_verkey, + mediator_diddoc, + ) + .await + .unwrap(); + // extract routing parameters + if let MediatorCoordMsgEnum::MediateGrant(grant_data) = + serde_json::from_str(&response_message).unwrap() + { + info!("Grant Data {:?}", grant_data); + grant_data + } else { + panic!( + "Should get response that is of type Mediator Grant. Found {:?}", + response_message + ) + } +} + +/// Register recipient keys with mediator +async fn gen_and_register_recipient_key( + agent: &mut Agent, + agent_aries_transport: &mut impl AriesTransport, + agent_verkey: &VerKey, + mediator_diddoc: &AriesDidDoc, +) -> Result<(VerKey, AriesDidDoc)> { + let agent_invite: OOBInvitation = agent + .get_oob_invite() + .map_err(|e| GenericStringError { msg: e.to_string() })?; + let agent_diddoc = oob2did(agent_invite); + let agent_recipient_key = agent_diddoc + .recipient_keys() + .unwrap() + .first() + .unwrap() + .clone(); + // register recipient key with mediator + let message = MediatorCoordMsgEnum::KeylistUpdateRequest(KeylistUpdateRequestData { + updates: vec![KeylistUpdateItem { + recipient_key: agent_recipient_key.clone(), + action: KeylistUpdateItemAction::Add, + result: None, + }], + }); + info!("Sending {:?}", serde_json::to_string(&message).unwrap()); + let message_bytes = serde_json::to_vec(&message)?; + let _response_message = send_message_and_pop_response_message( + &message_bytes, + agent, + agent_aries_transport, + agent_verkey, + mediator_diddoc, + ) + .await?; + Ok((agent_recipient_key, agent_diddoc)) +} + +async fn forward_dummy_anoncrypt_message( + agent_diddoc: &AriesDidDoc, + message_text: &str, +) -> Result<()> { + // Prepare forwarding agent + let agent_f = mediator::aries_agent::AgentBuilder::new_demo_agent().await?; + // Prepare forwarding agent transport + let mut agent_f_aries_transport = AriesReqwest { + response_queue: VecDeque::new(), + client: reqwest::Client::new(), + }; + // Prepare message and wrap into anoncrypt forward message + let message: BasicMessage = BasicMessage::builder() + .content( + BasicMessageContent::builder() + .content(message_text.to_string()) + .sent_time(chrono::DateTime::default()) + .build(), + ) + .decorators(BasicMessageDecorators::default()) + .id("JustHello".to_string()) + .build(); + + let EncryptionEnvelope(packed_message) = EncryptionEnvelope::create( + &*agent_f.get_wallet_ref(), + &serde_json::to_vec(&message)?, + None, + agent_diddoc, + ) + .await?; + // Send forward message to provided endpoint + let packed_json = serde_json::from_slice(&packed_message)?; + info!("Sending anoncrypt packed message{}", packed_json); + agent_f_aries_transport + .push_aries_envelope(packed_json, agent_diddoc) + .await?; + info!( + "Response of forward{:?}", + agent_f_aries_transport.pop_aries_envelope()? + ); + Ok(()) +} + +#[tokio::test] +async fn test_pickup_flow() -> Result<()> { + LOGGING_INIT.call_once(setup_env_logging); + // prepare receiver connection parameters + let (mut agent, mut agent_aries_transport, agent_verkey, mediator_diddoc) = + gen_mediator_connected_agent().await?; + // setup receiver routing + let grant_data = get_mediator_grant_data( + &agent, + &mut agent_aries_transport, + &agent_verkey, + &mediator_diddoc, + ) + .await; + agent + .init_service(grant_data.routing_keys, grant_data.endpoint.parse()?) + .await?; + // register recipient key with mediator + let (_agent_recipient_key, agent_diddoc) = gen_and_register_recipient_key( + &mut agent, + &mut agent_aries_transport, + &agent_verkey, + &mediator_diddoc, + ) + .await?; + // forward some messages. + forward_dummy_anoncrypt_message(&agent_diddoc, "Hi, from AgentF").await?; + forward_dummy_anoncrypt_message(&agent_diddoc, "Hi again, from AgentF").await?; + // Pickup flow + // // Status + let pickup_status_req = Pickup::StatusRequest( + StatusRequest::builder() + .content(StatusRequestContent::builder().build()) + .decorators(StatusRequestDecorators::default()) + .id("request-status".to_owned()) + .build(), + ); + let aries_message = AriesMessage::Pickup(pickup_status_req); + let message_bytes = serde_json::to_vec(&aries_message)?; + // send message and get response + let response_message = send_message_and_pop_response_message( + &message_bytes, + &agent, + &mut agent_aries_transport, + &agent_verkey, + &mediator_diddoc, + ) + .await?; + // Verify expected + if let AriesMessage::Pickup(Pickup::Status(status)) = serde_json::from_str(&response_message)? { + info!("Received status as expected {:?}", status); + assert_eq!(status.content.message_count, 2) + } else { + panic!( + "Expected status with message count = 2, received {:?}", + response_message + ) + } + // // Delivery + let pickup_delivery_req = Pickup::DeliveryRequest( + DeliveryRequest::builder() + .content(DeliveryRequestContent::builder().limit(10).build()) + .decorators(DeliveryRequestDecorators::builder().build()) + .id("request-delivery".to_owned()) + .build(), + ); + let aries_message = AriesMessage::Pickup(pickup_delivery_req); + let message_bytes = serde_json::to_vec(&aries_message)?; + // send message and get response + let response_message = send_message_and_pop_response_message( + &message_bytes, + &agent, + &mut agent_aries_transport, + &agent_verkey, + &mediator_diddoc, + ) + .await?; + // Verify expected + let delivery = if let AriesMessage::Pickup(Pickup::Delivery(delivery)) = + serde_json::from_str(&response_message)? + { + info!("Received delivery as expected {:?}", delivery); + assert_eq!(delivery.content.attach.len(), 2); + delivery + } else { + panic!( + "Expected delivery with num_attachment = 2, received {:?}", + response_message + ) + }; + // verify valid attachment + if let AttachmentType::Base64(base64message) = + &delivery.content.attach.first().unwrap().data.content + { + let encrypted_message_bytes = base64_url::decode(base64message)?; + info!( + "Decoding attachment to packed_message {}", + String::from_utf8(message_bytes.clone())? + ); + let unpack = agent.unpack_didcomm(&encrypted_message_bytes).await; + info!("Decoded attachment 1 {:?}", unpack); + } + + Ok(()) +} diff --git a/messages/src/msg_fields/protocols/pickup/mod.rs b/messages/src/msg_fields/protocols/pickup/mod.rs index cdc4ec2373..ca35edc799 100644 --- a/messages/src/msg_fields/protocols/pickup/mod.rs +++ b/messages/src/msg_fields/protocols/pickup/mod.rs @@ -7,7 +7,7 @@ mod status_request; use derive_more::From; use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; -use self::{ +pub use self::{ delivery::{Delivery, DeliveryContent, DeliveryDecorators}, delivery_request::{DeliveryRequest, DeliveryRequestContent, DeliveryRequestDecorators}, live_delivery_change::{ From fee40760e4a5f5999b988286d58adf89fc20a256 Mon Sep 17 00:00:00 2001 From: nain-F49FF806 <126972030+nain-F49FF806@users.noreply.github.com> Date: Thu, 2 Nov 2023 16:48:16 +0100 Subject: [PATCH 4/4] Refactor and strip down Aries transport abstraction and further code trimming (#1040) * Refactor and strip down Aries transport abstraction and further code trimming (#1040) Signed-off-by: Naian <126972030+nain-F49FF806@users.noreply.github.com> --- agents/rust/mediator/client-tui/src/lib.rs | 2 +- .../aries_agent/{client.rs => client/mod.rs} | 9 +- .../aries_agent/{ => client}/transports.rs | 26 ++--- agents/rust/mediator/src/aries_agent/mod.rs | 21 ---- .../tests/common/agent_and_transport_utils.rs | 60 ++++++++-- .../tests/mediator-aries-connection.rs | 2 +- .../mediator/tests/mediator-coord-protocol.rs | 107 ++---------------- .../tests/mediator-protocol-pickup.rs | 56 ++------- .../tests/mediator-routing-forward.rs | 67 +++-------- 9 files changed, 103 insertions(+), 247 deletions(-) rename agents/rust/mediator/src/aries_agent/{client.rs => client/mod.rs} (96%) rename agents/rust/mediator/src/aries_agent/{ => client}/transports.rs (70%) diff --git a/agents/rust/mediator/client-tui/src/lib.rs b/agents/rust/mediator/client-tui/src/lib.rs index 318593c678..12d664408f 100644 --- a/agents/rust/mediator/client-tui/src/lib.rs +++ b/agents/rust/mediator/client-tui/src/lib.rs @@ -2,7 +2,7 @@ use std::collections::VecDeque; use aries_vcx_core::wallet::base_wallet::BaseWallet; use mediation::storage::MediatorPersistence; -use mediator::aries_agent::{transports::AriesReqwest, ArcAgent}; +use mediator::aries_agent::{client::transports::AriesReqwest, ArcAgent}; use messages::msg_fields::protocols::out_of_band::invitation::Invitation as OOBInvitation; use serde_json::{json, Value}; diff --git a/agents/rust/mediator/src/aries_agent/client.rs b/agents/rust/mediator/src/aries_agent/client/mod.rs similarity index 96% rename from agents/rust/mediator/src/aries_agent/client.rs rename to agents/rust/mediator/src/aries_agent/client/mod.rs index e5ab35ece6..03cd832ebf 100644 --- a/agents/rust/mediator/src/aries_agent/client.rs +++ b/agents/rust/mediator/src/aries_agent/client/mod.rs @@ -22,8 +22,10 @@ use messages::{ AriesMessage, }; use test_utils::mockdata::mock_ledger::MockLedger; +pub mod transports; -use super::{transports::AriesTransport, Agent}; +use self::transports::AriesTransport; +use super::Agent; use crate::{aries_agent::utils::oob2did, utils::prelude::*}; // client role utilities @@ -112,10 +114,9 @@ impl Agent { "Sending Connection Request Envelope: {},", serde_json::to_string_pretty(&packed_aries_msg_json).unwrap() ); - aries_transport - .push_aries_envelope(packed_aries_msg_json, &oob2did(oob_invite)) + let response_envelope = aries_transport + .send_aries_envelope(packed_aries_msg_json, &oob2did(oob_invite)) .await?; - let response_envelope = aries_transport.pop_aries_envelope()?; info!( "Received Response envelope {:#?}, unpacking", serde_json::to_string_pretty(&response_envelope).unwrap() diff --git a/agents/rust/mediator/src/aries_agent/transports.rs b/agents/rust/mediator/src/aries_agent/client/transports.rs similarity index 70% rename from agents/rust/mediator/src/aries_agent/transports.rs rename to agents/rust/mediator/src/aries_agent/client/transports.rs index 1c3d905ed8..e26e2dc15e 100644 --- a/agents/rust/mediator/src/aries_agent/transports.rs +++ b/agents/rust/mediator/src/aries_agent/client/transports.rs @@ -2,7 +2,7 @@ use std::collections::VecDeque; use async_trait::async_trait; use diddoc_legacy::aries::diddoc::AriesDidDoc; -use log::info; +use log::debug; use serde_json::Value; #[derive(thiserror::Error, Debug)] @@ -21,12 +21,12 @@ impl AriesTransportError { #[async_trait] pub trait AriesTransport { - fn pop_aries_envelope(&mut self) -> Result; - async fn push_aries_envelope( + /// Send envelope to destination (defined in AriesDidDoc) and return response + async fn send_aries_envelope( &mut self, envelope_json: Value, destination: &AriesDidDoc, - ) -> Result<(), AriesTransportError>; + ) -> Result; } pub struct AriesReqwest { @@ -36,14 +36,18 @@ pub struct AriesReqwest { #[async_trait] impl AriesTransport for AriesReqwest { - async fn push_aries_envelope( + async fn send_aries_envelope( &mut self, envelope_json: Value, destination: &AriesDidDoc, - ) -> Result<(), AriesTransportError> { + ) -> Result { let oob_invited_endpoint = destination .get_endpoint() .expect("Service needs an endpoint"); + debug!( + "Packed: {:?}, sending", + serde_json::to_string(&envelope_json).unwrap() + ); let res = self .client .post(oob_invited_endpoint) @@ -57,13 +61,7 @@ impl AriesTransport for AriesReqwest { .json() .await .map_err(AriesTransportError::from_std_error)?; - info!("Received aries response{:?}", res_json); - self.response_queue.push_back(res_json); - Ok(()) - } - fn pop_aries_envelope(&mut self) -> Result { - self.response_queue.pop_front().ok_or(AriesTransportError { - msg: "No messages in queue".to_owned(), - }) + debug!("Received response envelope {:?}", res_json); + Ok(res_json) } } diff --git a/agents/rust/mediator/src/aries_agent/mod.rs b/agents/rust/mediator/src/aries_agent/mod.rs index 79f3bead2b..c4db4c94f2 100644 --- a/agents/rust/mediator/src/aries_agent/mod.rs +++ b/agents/rust/mediator/src/aries_agent/mod.rs @@ -25,12 +25,10 @@ use messages::{ }; use serde_json::json; -use self::transports::AriesTransport; use crate::utils::{prelude::*, structs::VerKey}; #[cfg(any(test, feature = "client"))] pub mod client; -pub mod transports; pub mod utils; #[derive(Clone)] @@ -143,25 +141,6 @@ impl Agent { .await .map_err(string_from_std_error) } - pub async fn pack_and_send_didcomm( - &self, - message: &[u8], - our_vk: &VerKey, - their_diddoc: &AriesDidDoc, - aries_transport: &mut impl AriesTransport, - ) -> Result<(), String> { - let EncryptionEnvelope(packed_message) = - self.pack_didcomm(message, our_vk, their_diddoc).await?; - let packed_json = serde_json::from_slice(&packed_message).map_err(string_from_std_error)?; - info!( - "Packed: {:?}, sending", - serde_json::to_string(&packed_json).unwrap() - ); - aries_transport - .push_aries_envelope(packed_json, their_diddoc) - .await - .map_err(string_from_std_error) - } pub async fn auth_and_get_details( &self, diff --git a/agents/rust/mediator/tests/common/agent_and_transport_utils.rs b/agents/rust/mediator/tests/common/agent_and_transport_utils.rs index f5fcb7a5d3..affdae211a 100644 --- a/agents/rust/mediator/tests/common/agent_and_transport_utils.rs +++ b/agents/rust/mediator/tests/common/agent_and_transport_utils.rs @@ -1,12 +1,18 @@ use std::collections::VecDeque; -use aries_vcx::protocols::connection::invitee::{states::completed::Completed, InviteeConnection}; +use aries_vcx::{ + protocols::connection::invitee::{states::completed::Completed, InviteeConnection}, + utils::encryption_envelope::EncryptionEnvelope, +}; use aries_vcx_core::wallet::base_wallet::BaseWallet; use diddoc_legacy::aries::diddoc::AriesDidDoc; -use mediation::storage::MediatorPersistence; +use mediation::{ + didcomm_types::mediator_coord_structs::{MediateGrantData, MediatorCoordMsgEnum}, + storage::MediatorPersistence, +}; use mediator::{ aries_agent::{ - transports::{AriesReqwest, AriesTransport}, + client::transports::{AriesReqwest, AriesTransport}, Agent, }, utils::{structs::VerKey, GenericStringError}, @@ -68,15 +74,53 @@ pub async fn send_message_and_pop_response_message( our_verkey: &VerKey, their_diddoc: &AriesDidDoc, ) -> Result { - agent - .pack_and_send_didcomm(message_bytes, our_verkey, their_diddoc, aries_transport) + // Wrap message in encrypted envelope + let EncryptionEnvelope(packed_message) = agent + .pack_didcomm(message_bytes, our_verkey, their_diddoc) .await - .map_err(|err| GenericStringError { msg: err })?; + .map_err(|e| GenericStringError { msg: e.to_string() })?; + let packed_json = serde_json::from_slice(&packed_message)?; + // Send serialized envelope over transport + let response_envelope = aries_transport + .send_aries_envelope(packed_json, their_diddoc) + .await?; // unpack - let response = aries_transport.pop_aries_envelope()?; let unpacked_response = agent - .unpack_didcomm(&serde_json::to_vec(&response).unwrap()) + .unpack_didcomm(&serde_json::to_vec(&response_envelope).unwrap()) .await .unwrap(); Ok(unpacked_response.message) } + +pub async fn get_mediator_grant_data( + agent: &Agent, + agent_aries_transport: &mut impl AriesTransport, + agent_verkey: &VerKey, + mediator_diddoc: &AriesDidDoc, +) -> MediateGrantData { + // prepare request message + let message = MediatorCoordMsgEnum::MediateRequest; + let message_bytes = serde_json::to_vec(&message).unwrap(); + // send message and get response + let response_message = send_message_and_pop_response_message( + &message_bytes, + agent, + agent_aries_transport, + agent_verkey, + mediator_diddoc, + ) + .await + .unwrap(); + // extract routing parameters + if let MediatorCoordMsgEnum::MediateGrant(grant_data) = + serde_json::from_str(&response_message).unwrap() + { + info!("Grant Data {:?}", grant_data); + grant_data + } else { + panic!( + "Should get response that is of type Mediator Grant. Found {:?}", + response_message + ) + } +} diff --git a/agents/rust/mediator/tests/mediator-aries-connection.rs b/agents/rust/mediator/tests/mediator-aries-connection.rs index 34e7634510..8644e847fe 100644 --- a/agents/rust/mediator/tests/mediator-aries-connection.rs +++ b/agents/rust/mediator/tests/mediator-aries-connection.rs @@ -1,7 +1,7 @@ mod common; use std::collections::VecDeque; -use mediator::aries_agent::transports::AriesReqwest; +use mediator::aries_agent::client::transports::AriesReqwest; use messages::msg_fields::protocols::out_of_band::invitation::Invitation as OOBInvitation; use reqwest::header::ACCEPT; diff --git a/agents/rust/mediator/tests/mediator-coord-protocol.rs b/agents/rust/mediator/tests/mediator-coord-protocol.rs index c07a6cd398..868aad9941 100644 --- a/agents/rust/mediator/tests/mediator-coord-protocol.rs +++ b/agents/rust/mediator/tests/mediator-coord-protocol.rs @@ -1,110 +1,21 @@ mod common; -use std::collections::VecDeque; -use aries_vcx::protocols::connection::invitee::{states::completed::Completed, InviteeConnection}; use aries_vcx_core::wallet::base_wallet::BaseWallet; -use diddoc_legacy::aries::diddoc::AriesDidDoc; -use mediation::{ - didcomm_types::mediator_coord_structs::{ - KeylistData, KeylistQueryData, KeylistUpdateItem, KeylistUpdateItemAction, - KeylistUpdateRequestData, MediatorCoordMsgEnum, - }, - storage::MediatorPersistence, +use mediation::didcomm_types::mediator_coord_structs::{ + KeylistData, KeylistQueryData, KeylistUpdateItem, KeylistUpdateItemAction, + KeylistUpdateRequestData, MediatorCoordMsgEnum, }; -use mediator::{ - aries_agent::{ - transports::{AriesReqwest, AriesTransport}, - Agent, + +use crate::common::{ + agent_and_transport_utils::{ + gen_mediator_connected_agent, send_message_and_pop_response_message, }, - utils::{structs::VerKey, GenericStringError}, + prelude::*, + test_setup::setup_env_logging, }; -use messages::msg_fields::protocols::out_of_band::invitation::Invitation as OOBInvitation; -use reqwest::header::ACCEPT; - -use crate::common::{prelude::*, test_setup::setup_env_logging}; static LOGGING_INIT: std::sync::Once = std::sync::Once::new(); -const ENDPOINT_ROOT: &str = "http://localhost:8005"; - -async fn didcomm_connection( - agent: &Agent, - aries_transport: &mut impl AriesTransport, -) -> Result> { - let client = reqwest::Client::new(); - let base: Url = ENDPOINT_ROOT.parse().unwrap(); - let endpoint_register = base.join("register").unwrap(); - - let oobi: OOBInvitation = client - .get(endpoint_register) - .header(ACCEPT, "application/json") - .send() - .await? - .error_for_status()? - .json() - .await?; - info!("Got invitation from register endpoint {:?}", oobi); - - let state: InviteeConnection = - agent.establish_connection(oobi, aries_transport).await?; - - Ok(state) -} - -/// Returns agent, aries transport for agent, agent's verkey, and mediator's diddoc. -async fn gen_mediator_connected_agent() -> Result<( - Agent, - impl AriesTransport, - VerKey, - AriesDidDoc, -)> { - let agent = mediator::aries_agent::AgentBuilder::new_demo_agent().await?; - let mut aries_transport = AriesReqwest { - response_queue: VecDeque::new(), - client: reqwest::Client::new(), - }; - let completed_connection = didcomm_connection(&agent, &mut aries_transport).await?; - let our_verkey: VerKey = completed_connection.pairwise_info().pw_vk.clone(); - let their_diddoc = completed_connection.their_did_doc().clone(); - Ok((agent, aries_transport, our_verkey, their_diddoc)) -} - -/// Sends message over didcomm connection and returns unpacked response message -async fn send_message_and_pop_response_message( - message_bytes: &[u8], - agent: &Agent, - aries_transport: &mut impl AriesTransport, - our_verkey: &VerKey, - their_diddoc: &AriesDidDoc, -) -> Result { - agent - .pack_and_send_didcomm(message_bytes, our_verkey, their_diddoc, aries_transport) - .await - .map_err(|err| GenericStringError { msg: err })?; - // unpack - let response = aries_transport.pop_aries_envelope()?; - let unpacked_response = agent - .unpack_didcomm(&serde_json::to_vec(&response).unwrap()) - .await - .unwrap(); - Ok(unpacked_response.message) -} - -#[tokio::test] -#[ignore] -async fn test_init() { - LOGGING_INIT.call_once(setup_env_logging); - let agent = mediator::aries_agent::AgentBuilder::new_demo_agent() - .await - .unwrap(); - let mut aries_transport = AriesReqwest { - response_queue: VecDeque::new(), - client: reqwest::Client::new(), - }; - let _ = didcomm_connection(&agent, &mut aries_transport).await; - let _ = didcomm_connection(&agent, &mut aries_transport).await; -} - #[tokio::test] async fn test_mediate_grant() -> Result<()> { LOGGING_INIT.call_once(setup_env_logging); diff --git a/agents/rust/mediator/tests/mediator-protocol-pickup.rs b/agents/rust/mediator/tests/mediator-protocol-pickup.rs index 2084b64510..13aaa176bf 100644 --- a/agents/rust/mediator/tests/mediator-protocol-pickup.rs +++ b/agents/rust/mediator/tests/mediator-protocol-pickup.rs @@ -6,14 +6,13 @@ use aries_vcx_core::wallet::base_wallet::BaseWallet; use diddoc_legacy::aries::diddoc::AriesDidDoc; use mediation::{ didcomm_types::mediator_coord_structs::{ - KeylistUpdateItem, KeylistUpdateItemAction, KeylistUpdateRequestData, MediateGrantData, - MediatorCoordMsgEnum, + KeylistUpdateItem, KeylistUpdateItemAction, KeylistUpdateRequestData, MediatorCoordMsgEnum, }, storage::MediatorPersistence, }; use mediator::{ aries_agent::{ - transports::{AriesReqwest, AriesTransport}, + client::transports::{AriesReqwest, AriesTransport}, utils::oob2did, Agent, }, @@ -34,7 +33,8 @@ use messages::{ use crate::common::{ agent_and_transport_utils::{ - gen_mediator_connected_agent, send_message_and_pop_response_message, + gen_mediator_connected_agent, get_mediator_grant_data, + send_message_and_pop_response_message, }, prelude::*, test_setup::setup_env_logging, @@ -42,39 +42,6 @@ use crate::common::{ static LOGGING_INIT: std::sync::Once = std::sync::Once::new(); -async fn get_mediator_grant_data( - agent: &Agent, - agent_aries_transport: &mut impl AriesTransport, - agent_verkey: &VerKey, - mediator_diddoc: &AriesDidDoc, -) -> MediateGrantData { - // prepare request message - let message = MediatorCoordMsgEnum::MediateRequest; - let message_bytes = serde_json::to_vec(&message).unwrap(); - // send message and get response - let response_message = send_message_and_pop_response_message( - &message_bytes, - agent, - agent_aries_transport, - agent_verkey, - mediator_diddoc, - ) - .await - .unwrap(); - // extract routing parameters - if let MediatorCoordMsgEnum::MediateGrant(grant_data) = - serde_json::from_str(&response_message).unwrap() - { - info!("Grant Data {:?}", grant_data); - grant_data - } else { - panic!( - "Should get response that is of type Mediator Grant. Found {:?}", - response_message - ) - } -} - /// Register recipient keys with mediator async fn gen_and_register_recipient_key( agent: &mut Agent, @@ -113,7 +80,7 @@ async fn gen_and_register_recipient_key( Ok((agent_recipient_key, agent_diddoc)) } -async fn forward_dummy_anoncrypt_message( +async fn forward_basic_anoncrypt_message( agent_diddoc: &AriesDidDoc, message_text: &str, ) -> Result<()> { @@ -146,13 +113,10 @@ async fn forward_dummy_anoncrypt_message( // Send forward message to provided endpoint let packed_json = serde_json::from_slice(&packed_message)?; info!("Sending anoncrypt packed message{}", packed_json); - agent_f_aries_transport - .push_aries_envelope(packed_json, agent_diddoc) + let response_envelope = agent_f_aries_transport + .send_aries_envelope(packed_json, agent_diddoc) .await?; - info!( - "Response of forward{:?}", - agent_f_aries_transport.pop_aries_envelope()? - ); + info!("Response of forward{:?}", response_envelope); Ok(()) } @@ -182,8 +146,8 @@ async fn test_pickup_flow() -> Result<()> { ) .await?; // forward some messages. - forward_dummy_anoncrypt_message(&agent_diddoc, "Hi, from AgentF").await?; - forward_dummy_anoncrypt_message(&agent_diddoc, "Hi again, from AgentF").await?; + forward_basic_anoncrypt_message(&agent_diddoc, "Hi, from AgentF").await?; + forward_basic_anoncrypt_message(&agent_diddoc, "Hi again, from AgentF").await?; // Pickup flow // // Status let pickup_status_req = Pickup::StatusRequest( diff --git a/agents/rust/mediator/tests/mediator-routing-forward.rs b/agents/rust/mediator/tests/mediator-routing-forward.rs index e5b91e8eb9..e09d2ca858 100644 --- a/agents/rust/mediator/tests/mediator-routing-forward.rs +++ b/agents/rust/mediator/tests/mediator-routing-forward.rs @@ -2,22 +2,15 @@ mod common; use std::collections::VecDeque; use aries_vcx::utils::encryption_envelope::EncryptionEnvelope; -use aries_vcx_core::wallet::base_wallet::BaseWallet; -use diddoc_legacy::aries::diddoc::AriesDidDoc; -use mediation::{ - didcomm_types::mediator_coord_structs::{ - KeylistUpdateItem, KeylistUpdateItemAction, KeylistUpdateRequestData, MediateGrantData, - MediatorCoordMsgEnum, - }, - storage::MediatorPersistence, +use mediation::didcomm_types::mediator_coord_structs::{ + KeylistUpdateItem, KeylistUpdateItemAction, KeylistUpdateRequestData, MediatorCoordMsgEnum, }; use mediator::{ aries_agent::{ - transports::{AriesReqwest, AriesTransport}, + client::transports::{AriesReqwest, AriesTransport}, utils::oob2did, - Agent, }, - utils::{structs::VerKey, GenericStringError}, + utils::GenericStringError, }; use messages::msg_fields::protocols::{ basic_message::{BasicMessage, BasicMessageContent, BasicMessageDecorators}, @@ -26,7 +19,8 @@ use messages::msg_fields::protocols::{ use crate::common::{ agent_and_transport_utils::{ - gen_mediator_connected_agent, send_message_and_pop_response_message, + gen_mediator_connected_agent, get_mediator_grant_data, + send_message_and_pop_response_message, }, prelude::*, test_setup::setup_env_logging, @@ -34,40 +28,6 @@ use crate::common::{ static LOGGING_INIT: std::sync::Once = std::sync::Once::new(); -async fn get_mediator_grant_data( - agent: &Agent, - agent_aries_transport: &mut impl AriesTransport, - agent_verkey: &VerKey, - mediator_diddoc: &AriesDidDoc, -) -> MediateGrantData { - // prepare request message - let message = MediatorCoordMsgEnum::MediateRequest; - let message_bytes = serde_json::to_vec(&message).unwrap(); - // send message and get response - let response_message = send_message_and_pop_response_message( - &message_bytes, - agent, - agent_aries_transport, - agent_verkey, - mediator_diddoc, - ) - .await - .unwrap(); - // extract routing parameters - - if let MediatorCoordMsgEnum::MediateGrant(grant_data) = - serde_json::from_str(&response_message).unwrap() - { - info!("Grant Data {:?}", grant_data); - grant_data - } else { - panic!( - "Should get response that is of type Mediator Grant. Found {:?}", - response_message - ) - } -} - #[tokio::test] async fn test_forward_flow() -> Result<()> { LOGGING_INIT.call_once(setup_env_logging); @@ -129,7 +89,10 @@ async fn test_forward_flow() -> Result<()> { .decorators(BasicMessageDecorators::default()) .id("JustHello".to_string()) .build(); - + info!( + "Prepared message {:?}, proceeding to anoncrypt wrap", + serde_json::to_string(&message).unwrap() + ); let EncryptionEnvelope(packed_message) = EncryptionEnvelope::create( &*agent.get_wallet_ref(), &serde_json::to_vec(&message)?, @@ -139,14 +102,10 @@ async fn test_forward_flow() -> Result<()> { .await?; // Send forward message to provided endpoint let packed_json = serde_json::from_slice(&packed_message)?; - info!("Sending anoncrypt packed message{}", packed_json); - agent_f_aries_transport - .push_aries_envelope(packed_json, &agent_diddoc) + let response = agent_f_aries_transport + .send_aries_envelope(packed_json, &agent_diddoc) .await?; - info!( - "Response of forward{:?}", - agent_f_aries_transport.pop_aries_envelope()? - ); + info!("Response of forward{:?}", response); Ok(()) }