diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 78efc4c4cd..989d8ff06f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -98,6 +98,9 @@ jobs: workspace_clippy: runs-on: ubuntu-20.04 + strategy: + matrix: + wallet: ["vdrtools_wallet", "askar_wallet"] steps: - name: "Git checkout" uses: actions/checkout@v3 @@ -113,7 +116,7 @@ jobs: sudo apt-get install -y libsodium-dev libssl-dev libzmq3-dev sudo snap install --edge --classic just - name: "Verify clippy across the entire workspace with default features" - run: just clippy-workspace + run: just clippy-workspace ${{ matrix.wallet }} aries_vcx_clippy: runs-on: ubuntu-20.04 @@ -392,6 +395,9 @@ jobs: needs: workflow-setup if: ${{ needs.workflow-setup.outputs.SKIP_CI != 'true' }} runs-on: ubuntu-20.04 + strategy: + matrix: + wallet: ["vdrtools_wallet", "askar_wallet"] steps: - name: "Git checkout" uses: actions/checkout@v3 @@ -402,7 +408,7 @@ jobs: - name: "Install just" run: sudo snap install --edge --classic just - name: "Run libvcx_core integration tests" - run: just test-integration-libvcx + run: just test-integration-libvcx ${{ matrix.wallet }} test-integration-did-crate: needs: workflow-setup diff --git a/Cargo.lock b/Cargo.lock index a6bf01c2f0..3852c754a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5976,6 +5976,8 @@ dependencies = [ "napi", "napi-build", "napi-derive", + "serde", + "serde_json", "uuid 1.5.0", "wallet_migrator", ] diff --git a/aries/agents/rust/aries-vcx-agent/src/agent/agent_config.rs b/aries/agents/rust/aries-vcx-agent/src/agent/agent_config.rs index 42e52ff008..d0fb2a1a64 100644 --- a/aries/agents/rust/aries-vcx-agent/src/agent/agent_config.rs +++ b/aries/agents/rust/aries-vcx-agent/src/agent/agent_config.rs @@ -1,9 +1,11 @@ -use aries_vcx_core::wallet::indy::{IssuerConfig, WalletConfig}; +use aries_vcx_core::wallet::{ + base_wallet::issuer_config::IssuerConfig, indy::indy_wallet_config::IndyWalletConfig, +}; use display_as_json::Display; use serde::Serialize; #[derive(Clone, Serialize, Display)] pub struct AgentConfig { - pub config_wallet: WalletConfig, + pub config_wallet: IndyWalletConfig, pub config_issuer: IssuerConfig, } diff --git a/aries/agents/rust/aries-vcx-agent/src/agent/agent_struct.rs b/aries/agents/rust/aries-vcx-agent/src/agent/agent_struct.rs index 98f4f345e0..0d410d81ab 100644 --- a/aries/agents/rust/aries-vcx-agent/src/agent/agent_struct.rs +++ b/aries/agents/rust/aries-vcx-agent/src/agent/agent_struct.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use aries_vcx_core::{ anoncreds::credx_anoncreds::IndyCredxAnonCreds, ledger::indy_vdr_ledger::{DefaultIndyLedgerRead, DefaultIndyLedgerWrite}, - wallet::indy::IndySdkWallet, + wallet::base_wallet::BaseWallet, }; use crate::{ @@ -18,25 +18,25 @@ use crate::{ }; #[derive(Clone)] -pub struct Agent { +pub struct Agent { pub(super) ledger_read: Arc, pub(super) ledger_write: Arc, pub(super) anoncreds: IndyCredxAnonCreds, - pub(super) wallet: Arc, + pub(super) wallet: Arc, pub(super) config: AgentConfig, - pub(super) connections: Arc, - pub(super) schemas: Arc, - pub(super) cred_defs: Arc, - pub(super) rev_regs: Arc, - pub(super) holder: Arc, - pub(super) issuer: Arc, - pub(super) verifier: Arc, - pub(super) prover: Arc, - pub(super) out_of_band: Arc, - pub(super) did_exchange: Arc, + pub(super) connections: Arc>, + pub(super) schemas: Arc>, + pub(super) cred_defs: Arc>, + pub(super) rev_regs: Arc>, + pub(super) holder: Arc>, + pub(super) issuer: Arc>, + pub(super) verifier: Arc>, + pub(super) prover: Arc>, + pub(super) out_of_band: Arc>, + pub(super) did_exchange: Arc>, } -impl Agent { +impl Agent { pub fn ledger_read(&self) -> &DefaultIndyLedgerRead { &self.ledger_read } @@ -49,7 +49,7 @@ impl Agent { &self.anoncreds } - pub fn wallet(&self) -> &IndySdkWallet { + pub fn wallet(&self) -> &Arc { &self.wallet } @@ -61,43 +61,43 @@ impl Agent { self.config.config_issuer.institution_did.clone() } - pub fn connections(&self) -> Arc { + pub fn connections(&self) -> Arc> { self.connections.clone() } - pub fn out_of_band(&self) -> Arc { + pub fn out_of_band(&self) -> Arc> { self.out_of_band.clone() } - pub fn did_exchange(&self) -> Arc { + pub fn did_exchange(&self) -> Arc> { self.did_exchange.clone() } - pub fn schemas(&self) -> Arc { + pub fn schemas(&self) -> Arc> { self.schemas.clone() } - pub fn cred_defs(&self) -> Arc { + pub fn cred_defs(&self) -> Arc> { self.cred_defs.clone() } - pub fn rev_regs(&self) -> Arc { + pub fn rev_regs(&self) -> Arc> { self.rev_regs.clone() } - pub fn issuer(&self) -> Arc { + pub fn issuer(&self) -> Arc> { self.issuer.clone() } - pub fn holder(&self) -> Arc { + pub fn holder(&self) -> Arc> { self.holder.clone() } - pub fn verifier(&self) -> Arc { + pub fn verifier(&self) -> Arc> { self.verifier.clone() } - pub fn prover(&self) -> Arc { + pub fn prover(&self) -> Arc> { self.prover.clone() } diff --git a/aries/agents/rust/aries-vcx-agent/src/agent/init.rs b/aries/agents/rust/aries-vcx-agent/src/agent/init.rs index efc5b5a152..430fb3729d 100644 --- a/aries/agents/rust/aries-vcx-agent/src/agent/init.rs +++ b/aries/agents/rust/aries-vcx-agent/src/agent/init.rs @@ -11,9 +11,9 @@ use aries_vcx_core::{ self, anoncreds::{base_anoncreds::BaseAnonCreds, credx_anoncreds::IndyCredxAnonCreds}, ledger::indy_vdr_ledger::DefaultIndyLedgerRead, - wallet::indy::{ - wallet::{create_and_open_wallet, wallet_configure_issuer}, - IndySdkWallet, WalletConfig, + wallet::{ + base_wallet::{BaseWallet, ManageWallet}, + indy::{indy_wallet_config::IndyWalletConfig, IndySdkWallet}, }, }; use did_peer::resolver::PeerDidResolver; @@ -59,9 +59,9 @@ pub struct InitConfig { pub service_endpoint: ServiceEndpoint, } -impl Agent { +impl Agent { pub async fn initialize(init_config: InitConfig) -> AgentResult { - let config_wallet = WalletConfig { + let config_wallet = IndyWalletConfig { wallet_name: init_config.wallet_config.wallet_name, wallet_key: init_config.wallet_config.wallet_key, wallet_key_derivation: init_config.wallet_config.wallet_kdf, @@ -72,13 +72,13 @@ impl Agent { rekey_derivation_method: None, }; - let wallet_handle = create_and_open_wallet(&config_wallet).await.unwrap(); - let config_issuer = wallet_configure_issuer(wallet_handle, &init_config.enterprise_seed) + config_wallet.create_wallet().await.unwrap(); + let wallet = Arc::new(config_wallet.open_wallet().await.unwrap()); + let config_issuer = wallet + .configure_issuer(&init_config.enterprise_seed) .await .unwrap(); - let wallet = Arc::new(IndySdkWallet::new(wallet_handle)); - use aries_vcx_core::ledger::indy_vdr_ledger::{build_ledger_components, VcxPoolConfig}; info!("dev_build_profile_modular >>"); diff --git a/aries/agents/rust/aries-vcx-agent/src/services/connection.rs b/aries/agents/rust/aries-vcx-agent/src/services/connection.rs index f5b4027ee0..c608c2a3b8 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/connection.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/connection.rs @@ -10,7 +10,9 @@ use aries_vcx::{ pairwise_info::PairwiseInfo, Connection, GenericConnection, State, ThinState, }, }; -use aries_vcx_core::{ledger::indy_vdr_ledger::DefaultIndyLedgerRead, wallet::indy::IndySdkWallet}; +use aries_vcx_core::{ + ledger::indy_vdr_ledger::DefaultIndyLedgerRead, wallet::base_wallet::BaseWallet, +}; use url::Url; use crate::{ @@ -21,17 +23,17 @@ use crate::{ pub type ServiceEndpoint = Url; -pub struct ServiceConnections { +pub struct ServiceConnections { ledger_read: Arc, - wallet: Arc, + wallet: Arc, service_endpoint: ServiceEndpoint, connections: Arc>, } -impl ServiceConnections { +impl ServiceConnections { pub fn new( ledger_read: Arc, - wallet: Arc, + wallet: Arc, service_endpoint: ServiceEndpoint, ) -> Self { Self { diff --git a/aries/agents/rust/aries-vcx-agent/src/services/credential_definition.rs b/aries/agents/rust/aries-vcx-agent/src/services/credential_definition.rs index f22c539cfe..e071f579bb 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/credential_definition.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/credential_definition.rs @@ -5,7 +5,7 @@ use aries_vcx::{common::primitives::credential_definition::CredentialDef, did_pa use aries_vcx_core::{ anoncreds::credx_anoncreds::IndyCredxAnonCreds, ledger::indy_vdr_ledger::{DefaultIndyLedgerRead, DefaultIndyLedgerWrite}, - wallet::indy::IndySdkWallet, + wallet::base_wallet::BaseWallet, }; use crate::{ @@ -13,20 +13,20 @@ use crate::{ storage::{object_cache::ObjectCache, Storage}, }; -pub struct ServiceCredentialDefinitions { +pub struct ServiceCredentialDefinitions { ledger_read: Arc, ledger_write: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, + wallet: Arc, cred_defs: ObjectCache, } -impl ServiceCredentialDefinitions { +impl ServiceCredentialDefinitions { pub fn new( ledger_read: Arc, ledger_write: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, + wallet: Arc, ) -> Self { Self { cred_defs: ObjectCache::new("cred-defs"), diff --git a/aries/agents/rust/aries-vcx-agent/src/services/did_exchange.rs b/aries/agents/rust/aries-vcx-agent/src/services/did_exchange.rs index 40dd0db3e7..cddb304895 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/did_exchange.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/did_exchange.rs @@ -13,7 +13,9 @@ use aries_vcx::{ }, transport::Transport, }; -use aries_vcx_core::{ledger::indy_vdr_ledger::DefaultIndyLedgerRead, wallet::indy::IndySdkWallet}; +use aries_vcx_core::{ + ledger::indy_vdr_ledger::DefaultIndyLedgerRead, wallet::base_wallet::BaseWallet, +}; use did_resolver_registry::ResolverRegistry; use super::connection::ServiceEndpoint; @@ -24,19 +26,19 @@ use crate::{ AgentError, AgentErrorKind, AgentResult, }; -pub struct ServiceDidExchange { +pub struct ServiceDidExchange { ledger_read: Arc, - wallet: Arc, + wallet: Arc, resolver_registry: Arc, service_endpoint: ServiceEndpoint, did_exchange: Arc>, public_did: String, } -impl ServiceDidExchange { +impl ServiceDidExchange { pub fn new( ledger_read: Arc, - wallet: Arc, + wallet: Arc, resolver_registry: Arc, service_endpoint: ServiceEndpoint, public_did: String, diff --git a/aries/agents/rust/aries-vcx-agent/src/services/holder.rs b/aries/agents/rust/aries-vcx-agent/src/services/holder.rs index 45a80b137b..ae4ff6ee36 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/holder.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/holder.rs @@ -13,7 +13,7 @@ use aries_vcx::{ }; use aries_vcx_core::{ anoncreds::credx_anoncreds::IndyCredxAnonCreds, ledger::indy_vdr_ledger::DefaultIndyLedgerRead, - wallet::indy::IndySdkWallet, + wallet::base_wallet::BaseWallet, }; use crate::{ @@ -38,20 +38,20 @@ impl HolderWrapper { } } -pub struct ServiceCredentialsHolder { +pub struct ServiceCredentialsHolder { ledger_read: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, + wallet: Arc, creds_holder: ObjectCache, - service_connections: Arc, + service_connections: Arc>, } -impl ServiceCredentialsHolder { +impl ServiceCredentialsHolder { pub fn new( ledger_read: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, - service_connections: Arc, + wallet: Arc, + service_connections: Arc>, ) -> Self { Self { service_connections, @@ -78,12 +78,15 @@ impl ServiceCredentialsHolder { propose_credential: ProposeCredentialV1, ) -> AgentResult { let connection = self.service_connections.get_by_id(connection_id)?; - let wallet = self.wallet.as_ref(); let mut holder = Holder::create("")?; holder.set_proposal(propose_credential.clone())?; connection - .send_message(wallet, &propose_credential.into(), &VcxHttpClient) + .send_message( + self.wallet.as_ref(), + &propose_credential.into(), + &VcxHttpClient, + ) .await?; self.creds_holder.insert( @@ -117,11 +120,15 @@ impl ServiceCredentialsHolder { (None, None) => return Err(AgentError::from_kind(AgentErrorKind::InvalidArguments)), }; let connection = self.service_connections.get_by_id(&connection_id)?; - let wallet = self.wallet.as_ref(); + let pw_did = connection.pairwise_info().pw_did.to_string(); let send_closure: SendClosure = Box::new(|msg: AriesMessage| { - Box::pin(async move { connection.send_message(wallet, &msg, &VcxHttpClient).await }) + Box::pin(async move { + connection + .send_message(self.wallet.as_ref(), &msg, &VcxHttpClient) + .await + }) }); let msg_response = holder .prepare_credential_request( @@ -146,7 +153,6 @@ impl ServiceCredentialsHolder { let mut holder = self.get_holder(thread_id)?; let connection_id = self.get_connection_id(thread_id)?; let connection = self.service_connections.get_by_id(&connection_id)?; - let wallet = self.wallet.as_ref(); holder .process_credential( @@ -160,9 +166,11 @@ impl ServiceCredentialsHolder { None => {} Some(msg_response) => { let send_closure: SendClosure = Box::new(|msg: AriesMessage| { - Box::pin( - async move { connection.send_message(wallet, &msg, &VcxHttpClient).await }, - ) + Box::pin(async move { + connection + .send_message(self.wallet.as_ref(), &msg, &VcxHttpClient) + .await + }) }); send_closure(msg_response).await?; } diff --git a/aries/agents/rust/aries-vcx-agent/src/services/issuer.rs b/aries/agents/rust/aries-vcx-agent/src/services/issuer.rs index ac9a8c6bcf..ba1f9aa769 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/issuer.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/issuer.rs @@ -11,7 +11,9 @@ use aries_vcx::{ }, protocols::{issuance::issuer::state_machine::IssuerState, SendClosure}, }; -use aries_vcx_core::{anoncreds::credx_anoncreds::IndyCredxAnonCreds, wallet::indy::IndySdkWallet}; +use aries_vcx_core::{ + anoncreds::credx_anoncreds::IndyCredxAnonCreds, wallet::base_wallet::BaseWallet, +}; use crate::{ error::*, @@ -35,18 +37,18 @@ impl IssuerWrapper { } } -pub struct ServiceCredentialsIssuer { +pub struct ServiceCredentialsIssuer { anoncreds: IndyCredxAnonCreds, - wallet: Arc, + wallet: Arc, creds_issuer: ObjectCache, - service_connections: Arc, + service_connections: Arc>, } -impl ServiceCredentialsIssuer { +impl ServiceCredentialsIssuer { pub fn new( anoncreds: IndyCredxAnonCreds, - wallet: Arc, - service_connections: Arc, + wallet: Arc, + service_connections: Arc>, ) -> Self { Self { service_connections, @@ -95,10 +97,12 @@ impl ServiceCredentialsIssuer { .build_credential_offer_msg(self.wallet.as_ref(), &self.anoncreds, offer_info, None) .await?; - let wallet = self.wallet.as_ref(); - let send_closure: SendClosure = Box::new(|msg: AriesMessage| { - Box::pin(async move { connection.send_message(wallet, &msg, &VcxHttpClient).await }) + Box::pin(async move { + connection + .send_message(self.wallet.as_ref(), &msg, &VcxHttpClient) + .await + }) }); let credential_offer = issuer.get_credential_offer_msg()?; @@ -146,10 +150,12 @@ impl ServiceCredentialsIssuer { } = self.creds_issuer.get(thread_id)?; let connection = self.service_connections.get_by_id(&connection_id)?; - let wallet = self.wallet.as_ref(); - let send_closure: SendClosure = Box::new(|msg: AriesMessage| { - Box::pin(async move { connection.send_message(wallet, &msg, &VcxHttpClient).await }) + Box::pin(async move { + connection + .send_message(self.wallet.as_ref(), &msg, &VcxHttpClient) + .await + }) }); issuer diff --git a/aries/agents/rust/aries-vcx-agent/src/services/out_of_band.rs b/aries/agents/rust/aries-vcx-agent/src/services/out_of_band.rs index 39c1925a2d..202b55c3b2 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/out_of_band.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/out_of_band.rs @@ -18,7 +18,7 @@ use aries_vcx::{ }, protocols::did_exchange::state_machine::generate_keypair, }; -use aries_vcx_core::wallet::indy::IndySdkWallet; +use aries_vcx_core::wallet::base_wallet::BaseWallet; use public_key::KeyType; use uuid::Uuid; @@ -28,14 +28,14 @@ use crate::{ AgentResult, }; -pub struct ServiceOutOfBand { - wallet: Arc, +pub struct ServiceOutOfBand { + wallet: Arc, service_endpoint: ServiceEndpoint, out_of_band: Arc>, } -impl ServiceOutOfBand { - pub fn new(wallet: Arc, service_endpoint: ServiceEndpoint) -> Self { +impl ServiceOutOfBand { + pub fn new(wallet: Arc, service_endpoint: ServiceEndpoint) -> Self { Self { wallet, service_endpoint, diff --git a/aries/agents/rust/aries-vcx-agent/src/services/prover.rs b/aries/agents/rust/aries-vcx-agent/src/services/prover.rs index c9fa6a9d49..ed257a84b7 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/prover.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/prover.rs @@ -13,7 +13,7 @@ use aries_vcx::{ }; use aries_vcx_core::{ anoncreds::credx_anoncreds::IndyCredxAnonCreds, ledger::indy_vdr_ledger::DefaultIndyLedgerRead, - wallet::indy::IndySdkWallet, + wallet::base_wallet::BaseWallet, }; use serde_json::Value; @@ -39,20 +39,20 @@ impl ProverWrapper { } } -pub struct ServiceProver { +pub struct ServiceProver { ledger_read: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, + wallet: Arc, provers: ObjectCache, - service_connections: Arc, + service_connections: Arc>, } -impl ServiceProver { +impl ServiceProver { pub fn new( ledger_read: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, - service_connections: Arc, + wallet: Arc, + service_connections: Arc>, ) -> Self { Self { service_connections, @@ -116,10 +116,14 @@ impl ServiceProver { let connection = self.service_connections.get_by_id(connection_id)?; let mut prover = Prover::create("")?; - let wallet = self.wallet.as_ref(); + let wallet = &self.wallet; let send_closure: SendClosure = Box::new(|msg: AriesMessage| { - Box::pin(async move { connection.send_message(wallet, &msg, &VcxHttpClient).await }) + Box::pin(async move { + connection + .send_message(wallet.as_ref(), &msg, &VcxHttpClient) + .await + }) }); let proposal = prover.build_presentation_proposal(proposal).await?; @@ -160,10 +164,14 @@ impl ServiceProver { ) .await?; - let wallet = self.wallet.as_ref(); + let wallet = &self.wallet; let send_closure: SendClosure = Box::new(|msg: AriesMessage| { - Box::pin(async move { connection.send_message(wallet, &msg, &VcxHttpClient).await }) + Box::pin(async move { + connection + .send_message(wallet.as_ref(), &msg, &VcxHttpClient) + .await + }) }); let message = prover.mark_presentation_sent()?; diff --git a/aries/agents/rust/aries-vcx-agent/src/services/revocation_registry.rs b/aries/agents/rust/aries-vcx-agent/src/services/revocation_registry.rs index c9808e6e90..9668cda7c5 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/revocation_registry.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/revocation_registry.rs @@ -8,7 +8,7 @@ use aries_vcx::{common::primitives::revocation_registry::RevocationRegistry, did use aries_vcx_core::{ anoncreds::credx_anoncreds::IndyCredxAnonCreds, ledger::indy_vdr_ledger::{DefaultIndyLedgerRead, DefaultIndyLedgerWrite}, - wallet::indy::IndySdkWallet, + wallet::base_wallet::BaseWallet, }; use crate::{ @@ -16,21 +16,21 @@ use crate::{ storage::{object_cache::ObjectCache, Storage}, }; -pub struct ServiceRevocationRegistries { +pub struct ServiceRevocationRegistries { ledger_write: Arc, ledger_read: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, + wallet: Arc, issuer_did: Did, rev_regs: ObjectCache, } -impl ServiceRevocationRegistries { +impl ServiceRevocationRegistries { pub fn new( ledger_write: Arc, ledger_read: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, + wallet: Arc, issuer_did: String, ) -> Self { Self { diff --git a/aries/agents/rust/aries-vcx-agent/src/services/schema.rs b/aries/agents/rust/aries-vcx-agent/src/services/schema.rs index 79806a8aa7..1d626c4635 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/schema.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/schema.rs @@ -7,7 +7,7 @@ use aries_vcx_core::{ base_ledger::AnoncredsLedgerRead, indy_vdr_ledger::{DefaultIndyLedgerRead, DefaultIndyLedgerWrite}, }, - wallet::indy::IndySdkWallet, + wallet::base_wallet::BaseWallet, }; use crate::{ @@ -15,21 +15,21 @@ use crate::{ storage::{object_cache::ObjectCache, Storage}, }; -pub struct ServiceSchemas { +pub struct ServiceSchemas { ledger_read: Arc, ledger_write: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, + wallet: Arc, issuer_did: Did, schemas: ObjectCache, } -impl ServiceSchemas { +impl ServiceSchemas { pub fn new( ledger_read: Arc, ledger_write: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, + wallet: Arc, issuer_did: String, ) -> Self { Self { diff --git a/aries/agents/rust/aries-vcx-agent/src/services/verifier.rs b/aries/agents/rust/aries-vcx-agent/src/services/verifier.rs index 623543816a..ec6dd0e9c8 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/verifier.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/verifier.rs @@ -18,7 +18,7 @@ use aries_vcx::{ }; use aries_vcx_core::{ anoncreds::credx_anoncreds::IndyCredxAnonCreds, ledger::indy_vdr_ledger::DefaultIndyLedgerRead, - wallet::indy::IndySdkWallet, + wallet::base_wallet::BaseWallet, }; use super::connection::ServiceConnections; @@ -43,20 +43,20 @@ impl VerifierWrapper { } } -pub struct ServiceVerifier { +pub struct ServiceVerifier { ledger_read: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, + wallet: Arc, verifiers: ObjectCache, - service_connections: Arc, + service_connections: Arc>, } -impl ServiceVerifier { +impl ServiceVerifier { pub fn new( ledger_read: Arc, anoncreds: IndyCredxAnonCreds, - wallet: Arc, - service_connections: Arc, + wallet: Arc, + service_connections: Arc>, ) -> Self { Self { service_connections, @@ -80,10 +80,12 @@ impl ServiceVerifier { Verifier::create_from_request("".to_string(), &request)? }; - let wallet = self.wallet.as_ref(); - let send_closure: SendClosure = Box::new(|msg: AriesMessage| { - Box::pin(async move { connection.send_message(wallet, &msg, &VcxHttpClient).await }) + Box::pin(async move { + connection + .send_message(self.wallet.as_ref(), &msg, &VcxHttpClient) + .await + }) }); let message = verifier.mark_presentation_request_sent()?; @@ -112,10 +114,13 @@ impl ServiceVerifier { connection_id, } = self.verifiers.get(thread_id)?; let connection = self.service_connections.get_by_id(&connection_id)?; - let wallet = self.wallet.as_ref(); let send_closure: SendClosure = Box::new(|msg: AriesMessage| { - Box::pin(async move { connection.send_message(wallet, &msg, &VcxHttpClient).await }) + Box::pin(async move { + connection + .send_message(self.wallet.as_ref(), &msg, &VcxHttpClient) + .await + }) }); let message = verifier diff --git a/aries/agents/rust/mediator/client-tui/src/lib.rs b/aries/agents/rust/mediator/client-tui/src/lib.rs index 717a8fe9d4..c59db8555e 100644 --- a/aries/agents/rust/mediator/client-tui/src/lib.rs +++ b/aries/agents/rust/mediator/client-tui/src/lib.rs @@ -4,7 +4,7 @@ use messages::msg_fields::protocols::out_of_band::invitation::Invitation as OOBI use serde_json::{json, Value}; pub async fn handle_register( - agent: ArcAgent, + agent: ArcAgent, oob_invite: OOBInvitation, ) -> Result { let mut aries_transport = reqwest::Client::new(); diff --git a/aries/agents/rust/mediator/client-tui/src/main.rs b/aries/agents/rust/mediator/client-tui/src/main.rs index fac5be2809..cb45125850 100644 --- a/aries/agents/rust/mediator/client-tui/src/main.rs +++ b/aries/agents/rust/mediator/client-tui/src/main.rs @@ -1,3 +1,5 @@ +use aries_vcx_core::wallet::indy::IndySdkWallet; + mod tui; /// Aries Agent TUI @@ -11,7 +13,9 @@ async fn main() { load_dot_env(); setup_logging(); log::info!("TUI initializing!"); - let agent = AgentBuilder::new_demo_agent().await.unwrap(); + let agent = AgentBuilder::::new_demo_agent() + .await + .unwrap(); tui::init_tui(agent).await; } diff --git a/aries/agents/rust/mediator/src/aries_agent/client/mod.rs b/aries/agents/rust/mediator/src/aries_agent/client/mod.rs index f47e87c898..988f71288f 100644 --- a/aries/agents/rust/mediator/src/aries_agent/client/mod.rs +++ b/aries/agents/rust/mediator/src/aries_agent/client/mod.rs @@ -31,7 +31,7 @@ use super::Agent; use crate::utils::prelude::*; // client role utilities -impl Agent { +impl Agent { /// Starting from a new connection object, tries to create connection request object for the /// specified OOB invite endpoint pub async fn gen_connection_request( diff --git a/aries/agents/rust/mediator/src/aries_agent/mod.rs b/aries/agents/rust/mediator/src/aries_agent/mod.rs index a3f3d814f6..4bdc05fef4 100644 --- a/aries/agents/rust/mediator/src/aries_agent/mod.rs +++ b/aries/agents/rust/mediator/src/aries_agent/mod.rs @@ -8,11 +8,10 @@ use aries_vcx::{ use aries_vcx_core::{ errors::error::AriesVcxCoreError, wallet::{ - base_wallet::BaseWallet, - indy::{wallet::create_and_open_wallet, IndySdkWallet, WalletConfig}, + base_wallet::{BaseWallet, ManageWallet}, + indy::indy_wallet_config::IndyWalletConfig, structs_io::UnpackMessageOutput, }, - WalletHandle, }; use diddoc_legacy::aries::{diddoc::AriesDidDoc, service::AriesService}; use messages::{ @@ -46,12 +45,12 @@ pub struct AgentBuilder { _type_wallet: PhantomData, } /// Constructors -impl AgentBuilder { +impl AgentBuilder { pub async fn new_from_wallet_config( - config: WalletConfig, - ) -> Result, AriesVcxCoreError> { - let wallet_handle: WalletHandle = create_and_open_wallet(&config).await?; - let wallet = Arc::new(IndySdkWallet::new(wallet_handle)); + config: impl ManageWallet, + ) -> Result, AriesVcxCoreError> { + let wallet = Arc::new(config.create_wallet().await?); + info!("Connecting to persistence layer"); let persistence = Arc::new(get_persistence().await); Ok(Agent { @@ -60,9 +59,9 @@ impl AgentBuilder { service: None, }) } - pub async fn new_demo_agent() -> Result, AriesVcxCoreError> - { - let config = WalletConfig { + pub async fn new_demo_agent( + ) -> Result, AriesVcxCoreError> { + let config = IndyWalletConfig { wallet_name: uuid::Uuid::new_v4().to_string(), wallet_key: "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY".into(), wallet_key_derivation: "RAW".into(), @@ -77,8 +76,8 @@ impl AgentBuilder { } // Utils -impl Agent { - pub fn get_wallet_ref(&self) -> Arc { +impl Agent { + pub fn get_wallet_ref(&self) -> Arc { self.wallet.clone() } pub fn get_persistence_ref(&self) -> Arc { @@ -235,6 +234,7 @@ mod test { protocols::oob::oob_invitation_to_legacy_did_doc, utils::encryption_envelope::EncryptionEnvelope, }; + use aries_vcx_core::wallet::indy::IndySdkWallet; use log::info; use serde_json::Value; use test_utils::mockdata::mock_ledger::MockLedger; @@ -245,7 +245,9 @@ mod test { pub async fn test_pack_unpack() { let message: Value = serde_json::from_str("{}").unwrap(); let message_bytes = serde_json::to_vec(&message).unwrap(); - let mut agent = AgentBuilder::new_demo_agent().await.unwrap(); + let mut agent = AgentBuilder::::new_demo_agent() + .await + .unwrap(); agent .init_service( vec![], diff --git a/aries/agents/rust/mediator/src/bin/mediator.rs b/aries/agents/rust/mediator/src/bin/mediator.rs index 58b6529fbd..d61171c6ef 100644 --- a/aries/agents/rust/mediator/src/bin/mediator.rs +++ b/aries/agents/rust/mediator/src/bin/mediator.rs @@ -1,3 +1,4 @@ +use aries_vcx_core::wallet::indy::IndySdkWallet; use log::info; use mediator::aries_agent::AgentBuilder; @@ -8,7 +9,9 @@ async fn main() { info!("Starting up mediator! ⚙️⚙️"); let endpoint_root = std::env::var("ENDPOINT_ROOT").unwrap_or("127.0.0.1:8005".into()); info!("Mediator endpoint root address {}", endpoint_root); - let mut agent = AgentBuilder::new_demo_agent().await.unwrap(); + let mut agent = AgentBuilder::::new_demo_agent() + .await + .unwrap(); agent .init_service( vec![], diff --git a/aries/agents/rust/mediator/src/didcomm_handlers/connection.rs b/aries/agents/rust/mediator/src/didcomm_handlers/connection.rs index 0bdee9ec62..c49153506a 100644 --- a/aries/agents/rust/mediator/src/didcomm_handlers/connection.rs +++ b/aries/agents/rust/mediator/src/didcomm_handlers/connection.rs @@ -3,7 +3,7 @@ use messages::msg_fields::protocols::connection::Connection; use super::{unhandled_aries_message, utils::prelude::*, ArcAgent}; -pub async fn handle_aries_connection( +pub async fn handle_aries_connection( agent: ArcAgent, connection: Connection, ) -> Result { diff --git a/aries/agents/rust/mediator/src/didcomm_handlers/forward.rs b/aries/agents/rust/mediator/src/didcomm_handlers/forward.rs index 2cd4074813..ba5539982a 100644 --- a/aries/agents/rust/mediator/src/didcomm_handlers/forward.rs +++ b/aries/agents/rust/mediator/src/didcomm_handlers/forward.rs @@ -5,7 +5,7 @@ use super::{utils::prelude::*, ArcAgent}; use crate::mediation::forward::handle_forward; pub async fn handle_routing_forward( - agent: ArcAgent, + agent: ArcAgent, forward: Forward, ) -> Result { info!("{:?}", forward); diff --git a/aries/agents/rust/mediator/src/didcomm_handlers/mediator_coord.rs b/aries/agents/rust/mediator/src/didcomm_handlers/mediator_coord.rs index 713bb3f0a7..083c7cd347 100644 --- a/aries/agents/rust/mediator/src/didcomm_handlers/mediator_coord.rs +++ b/aries/agents/rust/mediator/src/didcomm_handlers/mediator_coord.rs @@ -7,7 +7,7 @@ use uuid::Uuid; use super::utils::prelude::*; pub async fn handle_mediation_coord( - agent: &ArcAgent, + agent: &ArcAgent, coord_msg: CoordinateMediation, auth_pubkey: &str, ) -> Result { diff --git a/aries/agents/rust/mediator/src/didcomm_handlers/mod.rs b/aries/agents/rust/mediator/src/didcomm_handlers/mod.rs index b7bd23ad55..5c8ab246ca 100644 --- a/aries/agents/rust/mediator/src/didcomm_handlers/mod.rs +++ b/aries/agents/rust/mediator/src/didcomm_handlers/mod.rs @@ -27,7 +27,7 @@ pub fn unhandled_aries_message(message: impl Debug) -> String { format!("Don't know how to handle this message type {:#?}", message) } -pub async fn handle_aries( +pub async fn handle_aries( State(agent): State>, didcomm_msg: Bytes, ) -> Result, String> { diff --git a/aries/agents/rust/mediator/src/didcomm_handlers/pickup.rs b/aries/agents/rust/mediator/src/didcomm_handlers/pickup.rs index 7bb2571041..5645f4dfe6 100644 --- a/aries/agents/rust/mediator/src/didcomm_handlers/pickup.rs +++ b/aries/agents/rust/mediator/src/didcomm_handlers/pickup.rs @@ -4,7 +4,7 @@ use messages::msg_fields::protocols::pickup::Pickup; use super::utils::prelude::*; pub async fn handle_pickup_protocol( - agent: &ArcAgent, + agent: &ArcAgent, pickup_message: Pickup, auth_pubkey: &str, ) -> Result { diff --git a/aries/agents/rust/mediator/src/http_routes/mod.rs b/aries/agents/rust/mediator/src/http_routes/mod.rs index 882a01304f..0b54bc0b6f 100644 --- a/aries/agents/rust/mediator/src/http_routes/mod.rs +++ b/aries/agents/rust/mediator/src/http_routes/mod.rs @@ -19,7 +19,7 @@ use crate::{ pub async fn oob_invite_qr( headers: HeaderMap, - State(agent): State>, + State(agent): State>, ) -> Response { let Json(oob_json) = oob_invite_json(State(agent)).await; let preferred_mimetype = headers @@ -48,14 +48,14 @@ pub async fn oob_invite_qr( } pub async fn oob_invite_json( - State(agent): State>, + State(agent): State>, ) -> Json { let oob = agent.get_oob_invite().unwrap(); Json(serde_json::to_value(oob).unwrap()) } pub async fn handle_didcomm( - State(agent): State>, + State(agent): State>, didcomm_msg: Bytes, ) -> Result, String> { didcomm_handlers::handle_aries(State(agent), didcomm_msg).await diff --git a/aries/agents/rust/mediator/tests/common/agent_and_transport_utils.rs b/aries/agents/rust/mediator/tests/common/agent_and_transport_utils.rs index 9ea2ea7432..763779266a 100644 --- a/aries/agents/rust/mediator/tests/common/agent_and_transport_utils.rs +++ b/aries/agents/rust/mediator/tests/common/agent_and_transport_utils.rs @@ -5,7 +5,7 @@ use aries_vcx::{ }, utils::encryption_envelope::EncryptionEnvelope, }; -use aries_vcx_core::wallet::base_wallet::BaseWallet; +use aries_vcx_core::wallet::{base_wallet::BaseWallet, indy::IndySdkWallet}; use diddoc_legacy::aries::diddoc::AriesDidDoc; use mediator::{ aries_agent::{client::transports::AriesTransport, Agent}, @@ -31,7 +31,7 @@ use super::prelude::*; const ENDPOINT_ROOT: &str = "http://localhost:8005"; pub async fn didcomm_connection( - agent: &Agent, + agent: &Agent, aries_transport: &mut impl AriesTransport, ) -> Result> { let client = reqwest::Client::new(); @@ -56,12 +56,12 @@ pub async fn didcomm_connection( /// Returns agent, aries transport for agent, agent's verkey, and mediator's diddoc. pub async fn gen_mediator_connected_agent() -> Result<( - Agent, + Agent, impl AriesTransport, VerKey, AriesDidDoc, )> { - let agent = mediator::aries_agent::AgentBuilder::new_demo_agent().await?; + let agent = mediator::aries_agent::AgentBuilder::::new_demo_agent().await?; let mut aries_transport = reqwest::Client::new(); let completed_connection = didcomm_connection(&agent, &mut aries_transport).await?; let our_verkey: VerKey = completed_connection.pairwise_info().pw_vk.clone(); @@ -72,7 +72,7 @@ pub async fn gen_mediator_connected_agent() -> Result<( /// Sends message over didcomm connection and returns unpacked response message pub async fn send_message_and_pop_response_message( message_bytes: &[u8], - agent: &Agent, + agent: &Agent, aries_transport: &mut impl AriesTransport, our_verkey: &VerKey, their_diddoc: &AriesDidDoc, @@ -96,7 +96,7 @@ pub async fn send_message_and_pop_response_message( } /// Register recipient keys with mediator pub async fn gen_and_register_recipient_key( - agent: &mut Agent, + agent: &mut Agent, agent_aries_transport: &mut impl AriesTransport, agent_verkey: &VerKey, mediator_diddoc: &AriesDidDoc, @@ -141,7 +141,7 @@ pub async fn gen_and_register_recipient_key( } pub async fn get_mediator_grant_data( - agent: &Agent, + agent: &Agent, agent_aries_transport: &mut impl AriesTransport, agent_verkey: &VerKey, mediator_diddoc: &AriesDidDoc, diff --git a/aries/agents/rust/mediator/tests/mediator-aries-connection.rs b/aries/agents/rust/mediator/tests/mediator-aries-connection.rs index cf0d415646..4f47157189 100644 --- a/aries/agents/rust/mediator/tests/mediator-aries-connection.rs +++ b/aries/agents/rust/mediator/tests/mediator-aries-connection.rs @@ -1,5 +1,6 @@ mod common; +use aries_vcx_core::wallet::indy::IndySdkWallet; use messages::msg_fields::protocols::out_of_band::invitation::Invitation as OOBInvitation; use reqwest::header::ACCEPT; @@ -28,7 +29,7 @@ async fn didcomm_connection_succeeds() -> Result<()> { "Got invitation from register endpoint {}", serde_json::to_string_pretty(&oobi.clone()).unwrap() ); - let agent = mediator::aries_agent::AgentBuilder::new_demo_agent().await?; + let agent = mediator::aries_agent::AgentBuilder::::new_demo_agent().await?; let mut aries_transport = reqwest::Client::new(); let _state = agent .establish_connection(oobi, &mut aries_transport) diff --git a/aries/agents/rust/mediator/tests/mediator-coord-protocol.rs b/aries/agents/rust/mediator/tests/mediator-coord-protocol.rs index 2681477a96..126ca4ae4a 100644 --- a/aries/agents/rust/mediator/tests/mediator-coord-protocol.rs +++ b/aries/agents/rust/mediator/tests/mediator-coord-protocol.rs @@ -1,6 +1,6 @@ mod common; -use aries_vcx_core::wallet::base_wallet::DidWallet; +use aries_vcx_core::wallet::base_wallet::did_wallet::DidWallet; use messages::{ msg_fields::protocols::coordinate_mediation::{ keylist_update::{KeylistUpdateItem, KeylistUpdateItemAction}, diff --git a/aries/agents/rust/mediator/tests/mediator-protocol-pickup.rs b/aries/agents/rust/mediator/tests/mediator-protocol-pickup.rs index 25a55632e3..a8416fd563 100644 --- a/aries/agents/rust/mediator/tests/mediator-protocol-pickup.rs +++ b/aries/agents/rust/mediator/tests/mediator-protocol-pickup.rs @@ -1,6 +1,7 @@ mod common; use aries_vcx::utils::encryption_envelope::EncryptionEnvelope; +use aries_vcx_core::wallet::indy::IndySdkWallet; use diddoc_legacy::aries::diddoc::AriesDidDoc; use mediator::aries_agent::client::transports::AriesTransport; use messages::{ @@ -31,7 +32,7 @@ async fn forward_basic_anoncrypt_message( message_text: &str, ) -> Result<()> { // Prepare forwarding agent - let agent_f = mediator::aries_agent::AgentBuilder::new_demo_agent().await?; + let agent_f = mediator::aries_agent::AgentBuilder::::new_demo_agent().await?; // Prepare forwarding agent transport let mut agent_f_aries_transport = reqwest::Client::new(); // Prepare message and wrap into anoncrypt forward message @@ -47,7 +48,7 @@ async fn forward_basic_anoncrypt_message( .build(); let EncryptionEnvelope(packed_message) = EncryptionEnvelope::create( - &*agent_f.get_wallet_ref(), + agent_f.get_wallet_ref().as_ref(), &serde_json::to_vec(&message)?, None, agent_diddoc, diff --git a/aries/agents/rust/mediator/tests/mediator-routing-forward.rs b/aries/agents/rust/mediator/tests/mediator-routing-forward.rs index dfc3e11b31..663206ed9e 100644 --- a/aries/agents/rust/mediator/tests/mediator-routing-forward.rs +++ b/aries/agents/rust/mediator/tests/mediator-routing-forward.rs @@ -59,7 +59,7 @@ async fn test_forward_flow() -> Result<()> { serde_json::to_string(&message).unwrap() ); let EncryptionEnvelope(packed_message) = EncryptionEnvelope::create( - &*agent.get_wallet_ref(), + agent.get_wallet_ref().as_ref(), &serde_json::to_vec(&message)?, None, &agent_diddoc, diff --git a/aries/aries_vcx/src/utils/encryption_envelope.rs b/aries/aries_vcx/src/utils/encryption_envelope.rs index 8c3eae98e0..d4e7d16efc 100644 --- a/aries/aries_vcx/src/utils/encryption_envelope.rs +++ b/aries/aries_vcx/src/utils/encryption_envelope.rs @@ -259,7 +259,7 @@ pub mod unit_tests { use test_utils::devsetup::build_setup_profile; use super::*; - use crate::aries_vcx_core::wallet::base_wallet::DidWallet; + use crate::aries_vcx_core::wallet::base_wallet::did_wallet::DidWallet; #[tokio::test] async fn test_pack_unpack_anon() { diff --git a/aries/aries_vcx/tests/test_mysql_wallet.rs b/aries/aries_vcx/tests/test_mysql_wallet.rs index dd0c428822..b0b24c02b1 100644 --- a/aries/aries_vcx/tests/test_mysql_wallet.rs +++ b/aries/aries_vcx/tests/test_mysql_wallet.rs @@ -7,11 +7,8 @@ mod dbtests { use aries_vcx::global::settings; use aries_vcx_core::wallet::{ - base_wallet::DidWallet, - indy::{ - wallet::{close_wallet, create_and_open_wallet, wallet_configure_issuer}, - IndySdkWallet, WalletConfig, - }, + base_wallet::{did_wallet::DidWallet, BaseWallet, ManageWallet}, + indy::indy_wallet_config::IndyWalletConfig, }; use libvcx_logger::LibvcxDefaultLogger; @@ -34,7 +31,7 @@ mod dbtests { }) .to_string(); let enterprise_seed = "000000000000000000000000Trustee1"; - let config_wallet = WalletConfig::builder() + let config_wallet = IndyWalletConfig::builder() .wallet_name(format!("faber_wallet_{}", uuid::Uuid::new_v4())) .wallet_key(settings::DEFAULT_WALLET_KEY.into()) .wallet_key_derivation(settings::WALLET_KDF_RAW.into()) @@ -43,13 +40,12 @@ mod dbtests { .storage_credentials(storage_credentials) .build(); - let wallet_handle = create_and_open_wallet(&config_wallet).await?; - let _config_issuer = wallet_configure_issuer(wallet_handle, enterprise_seed).await?; + let wallet = config_wallet.create_wallet().await?; + wallet.configure_issuer(enterprise_seed).await?; - IndySdkWallet::new(wallet_handle) - .create_and_store_my_did(None, None) - .await?; - close_wallet(wallet_handle).await?; + wallet.create_and_store_my_did(None, None).await?; + + wallet.close_wallet().await?; Ok(()) } } diff --git a/aries/aries_vcx/tests/test_pool.rs b/aries/aries_vcx/tests/test_pool.rs index 1a4842e624..a8adff3a34 100644 --- a/aries/aries_vcx/tests/test_pool.rs +++ b/aries/aries_vcx/tests/test_pool.rs @@ -27,7 +27,7 @@ use aries_vcx_core::{ base_ledger::{AnoncredsLedgerRead, AnoncredsLedgerWrite}, indy::pool::test_utils::get_temp_file_path, }, - wallet::base_wallet::{BaseWallet, DidWallet}, + wallet::base_wallet::{did_wallet::DidWallet, BaseWallet}, }; use did_parser::Did; use diddoc_legacy::aries::service::AriesService; diff --git a/aries/aries_vcx/tests/utils/test_agent.rs b/aries/aries_vcx/tests/utils/test_agent.rs index 3d02d53bee..b6f6f0e9b2 100644 --- a/aries/aries_vcx/tests/utils/test_agent.rs +++ b/aries/aries_vcx/tests/utils/test_agent.rs @@ -8,7 +8,7 @@ use aries_vcx_core::{ ledger::base_ledger::{ AnoncredsLedgerRead, AnoncredsLedgerWrite, IndyLedgerRead, IndyLedgerWrite, }, - wallet::base_wallet::{BaseWallet, DidWallet}, + wallet::base_wallet::{did_wallet::DidWallet, BaseWallet}, }; use did_parser::Did; use test_utils::{ diff --git a/aries/aries_vcx_core/src/anoncreds/credx_anoncreds/mod.rs b/aries/aries_vcx_core/src/anoncreds/credx_anoncreds/mod.rs index 531660ff31..06978f96af 100644 --- a/aries/aries_vcx_core/src/anoncreds/credx_anoncreds/mod.rs +++ b/aries/aries_vcx_core/src/anoncreds/credx_anoncreds/mod.rs @@ -66,8 +66,11 @@ use crate::{ utils::{constants::ATTRS, json::AsTypeOrDeserializationError}, wallet::{ base_wallet::{ - record::Record, record_category::RecordCategory, search_filter::SearchFilter, - BaseWallet, RecordWallet, + record::{AllRecords, Record}, + record_category::RecordCategory, + record_wallet::RecordWallet, + search_filter::SearchFilter, + BaseWallet, }, record_tags::{RecordTag, RecordTags}, }, @@ -87,6 +90,10 @@ struct WalletAdapter(Arc); #[async_trait] impl RecordWallet for WalletAdapter { + async fn all_records(&self) -> VcxCoreResult> { + self.0.all_records().await + } + async fn add_record(&self, record: Record) -> VcxCoreResult<()> { self.0.add_record(record).await } diff --git a/aries/aries_vcx_core/src/wallet/agency_client_wallet.rs b/aries/aries_vcx_core/src/wallet/agency_client_wallet.rs index 7e40cb38a6..cd8dfbd26b 100644 --- a/aries/aries_vcx_core/src/wallet/agency_client_wallet.rs +++ b/aries/aries_vcx_core/src/wallet/agency_client_wallet.rs @@ -9,8 +9,14 @@ use public_key::{Key, KeyType}; use super::{ base_wallet::{ - did_data::DidData, record::Record, record_category::RecordCategory, - search_filter::SearchFilter, BaseWallet, DidWallet, RecordWallet, + did_data::DidData, + did_wallet::DidWallet, + issuer_config::IssuerConfig, + record::{AllRecords, Record}, + record_category::RecordCategory, + record_wallet::RecordWallet, + search_filter::SearchFilter, + BaseWallet, }, record_tags::RecordTags, structs_io::UnpackMessageOutput, @@ -22,11 +28,31 @@ pub struct AgencyClientWallet { inner: Arc, } -impl BaseWallet for AgencyClientWallet {} +#[allow(unused_variables)] +#[async_trait] +impl BaseWallet for AgencyClientWallet { + async fn export_wallet(&self, path: &str, backup_key: &str) -> VcxCoreResult<()> { + Err(unimplemented_agency_client_wallet_method("export_wallet")) + } + + async fn close_wallet(&self) -> VcxCoreResult<()> { + Err(unimplemented_agency_client_wallet_method("close_wallet")) + } + + async fn configure_issuer(&self, key_seed: &str) -> VcxCoreResult { + Err(unimplemented_agency_client_wallet_method( + "configure_issuer", + )) + } +} #[allow(unused_variables)] #[async_trait] impl RecordWallet for AgencyClientWallet { + async fn all_records(&self) -> VcxCoreResult> { + Err(unimplemented_agency_client_wallet_method("get_all")) + } + async fn add_record(&self, record: Record) -> VcxCoreResult<()> { Err(unimplemented_agency_client_wallet_method("add_record")) } diff --git a/aries/aries_vcx_core/src/wallet/askar/all_askar_records.rs b/aries/aries_vcx_core/src/wallet/askar/all_askar_records.rs new file mode 100644 index 0000000000..cda61a9a9b --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/askar/all_askar_records.rs @@ -0,0 +1,31 @@ +use async_trait::async_trait; + +use crate::{ + errors::error::VcxCoreResult, + wallet::base_wallet::record::{AllRecords, PartialRecord}, +}; + +pub struct AllAskarRecords { + iterator: std::vec::IntoIter, + total_count: Option, +} + +impl AllAskarRecords { + pub fn new(iterator: std::vec::IntoIter, total_count: Option) -> Self { + Self { + iterator, + total_count, + } + } +} + +#[async_trait] +impl AllRecords for AllAskarRecords { + fn total_count(&self) -> VcxCoreResult> { + Ok(self.total_count) + } + + async fn next(&mut self) -> VcxCoreResult> { + Ok(self.iterator.next()) + } +} diff --git a/aries/aries_vcx_core/src/wallet/askar/askar_did_wallet.rs b/aries/aries_vcx_core/src/wallet/askar/askar_did_wallet.rs index d1ea85cd51..261b556771 100644 --- a/aries/aries_vcx_core/src/wallet/askar/askar_did_wallet.rs +++ b/aries/aries_vcx_core/src/wallet/askar/askar_did_wallet.rs @@ -16,7 +16,7 @@ use super::{ use crate::{ errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind, VcxCoreResult}, wallet::{ - base_wallet::{did_data::DidData, record_category::RecordCategory, DidWallet}, + base_wallet::{did_data::DidData, did_wallet::DidWallet, record_category::RecordCategory}, structs_io::UnpackMessageOutput, utils::did_from_key, }, diff --git a/aries/aries_vcx_core/src/wallet/askar/askar_import_config.rs b/aries/aries_vcx_core/src/wallet/askar/askar_import_config.rs new file mode 100644 index 0000000000..35630d6a52 --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/askar/askar_import_config.rs @@ -0,0 +1,12 @@ +use serde::Deserialize; + +use crate::errors::error::VcxCoreResult; + +#[derive(Deserialize)] +pub struct AskarImportConfig {} + +impl AskarImportConfig { + pub async fn import_wallet(&self) -> VcxCoreResult<()> { + todo!() + } +} diff --git a/aries/aries_vcx_core/src/wallet/askar/askar_record_wallet.rs b/aries/aries_vcx_core/src/wallet/askar/askar_record_wallet.rs index bdba4a2ea5..c3e11ded1c 100644 --- a/aries/aries_vcx_core/src/wallet/askar/askar_record_wallet.rs +++ b/aries/aries_vcx_core/src/wallet/askar/askar_record_wallet.rs @@ -1,13 +1,15 @@ use aries_askar::entry::EntryTag; use async_trait::async_trait; -use super::AskarWallet; +use super::{all_askar_records::AllAskarRecords, AskarWallet}; use crate::{ errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind, VcxCoreResult}, wallet::{ base_wallet::{ - record::Record, record_category::RecordCategory, search_filter::SearchFilter, - RecordWallet, + record::{AllRecords, PartialRecord, Record}, + record_category::RecordCategory, + record_wallet::RecordWallet, + search_filter::SearchFilter, }, record_tags::RecordTags, }, @@ -132,4 +134,33 @@ impl RecordWallet for AskarWallet { .into_iter() .collect::>()?) } + + async fn all_records(&self) -> VcxCoreResult> { + let mut session = self.session().await?; + + let recs = session.fetch_all(None, None, None, false).await?; + + let mut recs = recs + .into_iter() + .map(PartialRecord::from_askar_entry) + .collect::, _>>()?; + + let keys = session + .fetch_all_keys(None, None, None, None, false) + .await?; + + let mut local_keys = keys + .into_iter() + .map(PartialRecord::from_askar_key_entry) + .collect::, _>>()?; + + recs.append(&mut local_keys); + + let total_count = recs.len(); + + Ok(Box::new(AllAskarRecords::new( + recs.into_iter(), + Some(total_count), + ))) + } } diff --git a/aries/aries_vcx_core/src/wallet/askar/askar_utils.rs b/aries/aries_vcx_core/src/wallet/askar/askar_utils.rs index 782aaf7fb3..80bdfbf966 100644 --- a/aries/aries_vcx_core/src/wallet/askar/askar_utils.rs +++ b/aries/aries_vcx_core/src/wallet/askar/askar_utils.rs @@ -1,4 +1,7 @@ -use aries_askar::kms::{KeyAlg, LocalKey}; +use aries_askar::{ + entry::Entry, + kms::{KeyAlg, LocalKey}, +}; use public_key::{Key, KeyType}; use serde::Deserialize; @@ -16,6 +19,10 @@ pub fn local_key_to_bs58_public_key(local_key: &LocalKey) -> VcxCoreResult VcxCoreResult { + Ok(bs58::encode(local_key.to_secret_bytes()?).into_string()) +} + pub fn local_key_to_public_key(local_key: &LocalKey) -> VcxCoreResult { Ok(Key::new( local_key.to_public_bytes()?.to_vec(), @@ -53,3 +60,9 @@ pub fn bytes_to_string(vec: Vec) -> VcxCoreResult { String::from_utf8(vec) .map_err(|err| AriesVcxCoreError::from_msg(AriesVcxCoreErrorKind::InvalidInput, err)) } + +pub fn value_from_entry(entry: Entry) -> VcxCoreResult { + Ok(std::str::from_utf8(&entry.value) + .map_err(|err| AriesVcxCoreError::from_msg(AriesVcxCoreErrorKind::WalletError, err))? + .to_string()) +} diff --git a/aries/aries_vcx_core/src/wallet/askar/askar_wallet_config.rs b/aries/aries_vcx_core/src/wallet/askar/askar_wallet_config.rs new file mode 100644 index 0000000000..b3dd94e644 --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/askar/askar_wallet_config.rs @@ -0,0 +1,58 @@ +use async_trait::async_trait; +use serde::Deserialize; + +use super::{key_method::KeyMethod, AskarWallet}; +use crate::{errors::error::VcxCoreResult, wallet::base_wallet::ManageWallet}; + +#[derive(Clone, Debug, Deserialize)] +pub struct AskarWalletConfig { + pub db_url: String, + pub key_method: KeyMethod, + pub pass_key: String, + pub profile: String, +} + +impl AskarWalletConfig { + pub fn new(db_url: &str, key_method: KeyMethod, pass_key: &str, profile: &str) -> Self { + Self { + db_url: db_url.into(), + key_method, + pass_key: pass_key.into(), + profile: profile.into(), + } + } + + pub fn db_url(&self) -> &str { + &self.db_url + } + + pub fn key_method(&self) -> &KeyMethod { + &self.key_method + } + + pub fn pass_key(&self) -> &str { + &self.pass_key + } + + pub fn profile(&self) -> &str { + &self.profile + } +} + +#[async_trait] +impl ManageWallet for AskarWalletConfig { + type ManagedWalletType = AskarWallet; + + async fn create_wallet(&self) -> VcxCoreResult { + let askar_wallet = AskarWallet::create(self, false).await?; + Ok(askar_wallet) + } + + async fn open_wallet(&self) -> VcxCoreResult { + Ok(AskarWallet::open(self).await?) + } + + async fn delete_wallet(&self) -> VcxCoreResult<()> { + todo!(); + } +} diff --git a/aries/aries_vcx_core/src/wallet/askar/key_method.rs b/aries/aries_vcx_core/src/wallet/askar/key_method.rs new file mode 100644 index 0000000000..c78e6690fe --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/askar/key_method.rs @@ -0,0 +1,50 @@ +use aries_askar::{ + storage::{Argon2Level, KdfMethod}, + StoreKeyMethod, +}; +use serde::Deserialize; + +#[derive(Debug, Copy, Clone, Deserialize)] +pub enum KeyMethod { + DeriveKey { inner: AskarKdfMethod }, + RawKey, + Unprotected, +} + +impl From for StoreKeyMethod { + fn from(value: KeyMethod) -> Self { + match value { + KeyMethod::DeriveKey { inner: payload } => StoreKeyMethod::DeriveKey(payload.into()), + KeyMethod::RawKey => StoreKeyMethod::RawKey, + KeyMethod::Unprotected => StoreKeyMethod::Unprotected, + } + } +} + +#[derive(Copy, Clone, Debug, Deserialize)] +pub enum AskarKdfMethod { + Argon2i { inner: ArgonLevel }, +} + +impl From for KdfMethod { + fn from(value: AskarKdfMethod) -> Self { + match value { + AskarKdfMethod::Argon2i { inner: payload } => KdfMethod::Argon2i(payload.into()), + } + } +} + +#[derive(Copy, Clone, Debug, Deserialize)] +pub enum ArgonLevel { + Interactive, + Moderate, +} + +impl From for Argon2Level { + fn from(value: ArgonLevel) -> Self { + match value { + ArgonLevel::Interactive => Argon2Level::Interactive, + ArgonLevel::Moderate => Argon2Level::Moderate, + } + } +} diff --git a/aries/aries_vcx_core/src/wallet/askar/key_value.rs b/aries/aries_vcx_core/src/wallet/askar/key_value.rs new file mode 100644 index 0000000000..23b09c0c9e --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/askar/key_value.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct KeyValue { + verkey: String, + signkey: String, +} + +impl KeyValue { + pub fn new(signkey: String, verkey: String) -> Self { + Self { signkey, verkey } + } +} diff --git a/aries/aries_vcx_core/src/wallet/askar/mod.rs b/aries/aries_vcx_core/src/wallet/askar/mod.rs index f78ac879a1..983bfe0f37 100644 --- a/aries/aries_vcx_core/src/wallet/askar/mod.rs +++ b/aries/aries_vcx_core/src/wallet/askar/mod.rs @@ -1,21 +1,31 @@ use aries_askar::{ entry::EntryTag, kms::{KeyAlg, KeyEntry, LocalKey}, - PassKey, Session, Store, StoreKeyMethod, + Session, Store, }; +use async_trait::async_trait; use public_key::Key; -use self::{askar_utils::local_key_to_bs58_name, rng_method::RngMethod}; +use self::{ + askar_utils::local_key_to_bs58_name, askar_wallet_config::AskarWalletConfig, + rng_method::RngMethod, +}; use super::base_wallet::{did_value::DidValue, record_category::RecordCategory, BaseWallet}; use crate::errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind, VcxCoreResult}; +mod all_askar_records; mod askar_did_wallet; +pub mod askar_import_config; mod askar_record_wallet; mod askar_utils; +pub mod askar_wallet_config; mod entry; mod entry_tags; +pub mod key_method; +mod key_value; mod pack; mod packing_types; +mod partial_record; mod rng_method; mod sig_type; mod unpack; @@ -26,34 +36,47 @@ pub struct AskarWallet { profile: String, } -impl BaseWallet for AskarWallet {} +#[async_trait] +impl BaseWallet for AskarWallet { + async fn export_wallet(&self, _path: &str, _backup_key: &str) -> VcxCoreResult<()> { + todo!() + } + + async fn close_wallet(&self) -> VcxCoreResult<()> { + todo!() + } +} impl AskarWallet { pub async fn create( - db_url: &str, - key_method: StoreKeyMethod, - pass_key: PassKey<'_>, + wallet_config: &AskarWalletConfig, recreate: bool, - profile: &str, ) -> Result { - let backend = - Store::provision(db_url, key_method, pass_key, Some(profile.into()), recreate).await?; + let backend = Store::provision( + wallet_config.db_url(), + (*wallet_config.key_method()).into(), + wallet_config.pass_key().into(), + Some(wallet_config.profile().to_owned()), + recreate, + ) + .await?; Ok(Self { backend, - profile: profile.into(), + profile: wallet_config.profile().into(), }) } - pub async fn open( - db_url: &str, - key_method: Option, - pass_key: PassKey<'_>, - profile: &str, - ) -> Result { + pub async fn open(wallet_config: &AskarWalletConfig) -> Result { Ok(Self { - backend: Store::open(db_url, key_method, pass_key, Some(profile.into())).await?, - profile: profile.into(), + backend: Store::open( + wallet_config.db_url(), + Some((*wallet_config.key_method()).into()), + wallet_config.pass_key().into(), + Some(wallet_config.profile().into()), + ) + .await?, + profile: wallet_config.profile().into(), }) } @@ -177,24 +200,22 @@ impl AskarWallet { #[cfg(test)] pub mod tests { - use crate::wallet::base_wallet::BaseWallet; + use super::AskarWallet; + use crate::wallet::{ + askar::{askar_wallet_config::AskarWalletConfig, key_method::KeyMethod}, + base_wallet::ManageWallet, + }; - pub async fn dev_setup_askar_wallet() -> Box { - use aries_askar::StoreKeyMethod; + pub async fn dev_setup_askar_wallet() -> AskarWallet { use uuid::Uuid; - use crate::wallet::askar::AskarWallet; + let config = AskarWalletConfig::new( + "sqlite://:memory:", + KeyMethod::Unprotected, + "", + &Uuid::new_v4().to_string(), + ); - Box::new( - AskarWallet::create( - "sqlite://:memory:", - StoreKeyMethod::Unprotected, - None.into(), - true, - &Uuid::new_v4().to_string(), - ) - .await - .unwrap(), - ) + config.create_wallet().await.unwrap() } } diff --git a/aries/aries_vcx_core/src/wallet/askar/partial_record.rs b/aries/aries_vcx_core/src/wallet/askar/partial_record.rs new file mode 100644 index 0000000000..5665de0485 --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/askar/partial_record.rs @@ -0,0 +1,39 @@ +use super::{askar_utils::value_from_entry, key_value::KeyValue}; +use crate::{ + errors::error::VcxCoreResult, + wallet::{ + askar::askar_utils::{local_key_to_bs58_private_key, local_key_to_bs58_public_key}, + base_wallet::{record::PartialRecord, record_category::RecordCategory}, + }, +}; + +impl PartialRecord { + pub fn from_askar_entry(entry: aries_askar::entry::Entry) -> VcxCoreResult { + Ok(Self::builder() + .name(entry.name.clone()) + .category(Some(entry.category.clone())) + .value(Some(value_from_entry(entry.clone())?)) + .tags(Some(entry.tags.into())) + .build()) + } + + pub fn from_askar_key_entry(key_entry: aries_askar::kms::KeyEntry) -> VcxCoreResult { + let local_key = key_entry.load_local_key()?; + let name = key_entry.name(); + let tags = key_entry.tags_as_slice(); + + let value = KeyValue::new( + local_key_to_bs58_private_key(&local_key)?, + local_key_to_bs58_public_key(&local_key)?, + ); + + let value = serde_json::to_string(&value)?; + + Ok(Self::builder() + .name(name.into()) + .category(Some(RecordCategory::Key.to_string())) + .value(Some(value)) + .tags(Some(tags.to_vec().into())) + .build()) + } +} diff --git a/aries/aries_vcx_core/src/wallet/base_wallet/did_wallet.rs b/aries/aries_vcx_core/src/wallet/base_wallet/did_wallet.rs new file mode 100644 index 0000000000..cf2aa62b41 --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/base_wallet/did_wallet.rs @@ -0,0 +1,35 @@ +use async_trait::async_trait; +use public_key::Key; + +use super::did_data::DidData; +use crate::{errors::error::VcxCoreResult, wallet::structs_io::UnpackMessageOutput}; + +#[async_trait] +pub trait DidWallet { + async fn create_and_store_my_did( + &self, + seed: Option<&str>, + kdf_method_name: Option<&str>, + ) -> VcxCoreResult; + + async fn key_count(&self) -> VcxCoreResult; + + async fn key_for_did(&self, did: &str) -> VcxCoreResult; + + async fn replace_did_key_start(&self, did: &str, seed: Option<&str>) -> VcxCoreResult; + + async fn replace_did_key_apply(&self, did: &str) -> VcxCoreResult<()>; + + async fn sign(&self, key: &Key, msg: &[u8]) -> VcxCoreResult>; + + async fn verify(&self, key: &Key, msg: &[u8], signature: &[u8]) -> VcxCoreResult; + + async fn pack_message( + &self, + sender_vk: Option, + receiver_keys: Vec, + msg: &[u8], + ) -> VcxCoreResult>; + + async fn unpack_message(&self, msg: &[u8]) -> VcxCoreResult; +} diff --git a/aries/aries_vcx_core/src/wallet/base_wallet/issuer_config.rs b/aries/aries_vcx_core/src/wallet/base_wallet/issuer_config.rs new file mode 100644 index 0000000000..82bc01fec0 --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/base_wallet/issuer_config.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +#[derive(Clone, Debug, TypedBuilder, Serialize, Deserialize)] +#[builder(field_defaults(default))] +pub struct IssuerConfig { + pub institution_did: String, +} diff --git a/aries/aries_vcx_core/src/wallet/base_wallet/migrate.rs b/aries/aries_vcx_core/src/wallet/base_wallet/migrate.rs new file mode 100644 index 0000000000..d3fdd087f8 --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/base_wallet/migrate.rs @@ -0,0 +1,120 @@ +use super::{record::Record, BaseWallet}; +use crate::{ + errors::error::{AriesVcxCoreErrorKind, VcxCoreResult}, + wallet::record_tags::RecordTags, +}; + +#[derive(Debug)] +pub struct MigrationStats { + migrated: u32, + skipped: u32, + duplicated: u32, + failed: u32, +} + +pub async fn migrate_records( + src_wallet: &impl BaseWallet, + dest_wallet: &impl BaseWallet, + mut migrate_fn: impl FnMut(Record) -> Result, E>, +) -> VcxCoreResult +where + E: std::fmt::Display, +{ + let mut records = src_wallet.all_records().await?; + let total = records.total_count(); + info!("Migrating {total:?} records"); + let mut num_record = 0; + let mut migration_result = MigrationStats { + migrated: 0, + skipped: 0, + duplicated: 0, + failed: 0, + }; + + while let Some(source_record) = records.next().await? { + num_record += 1; + if num_record % 1000 == 1 { + warn!( + "Migrating wallet record number {num_record} / {total:?}, intermediary migration \ + result: ${migration_result:?}" + ); + } + trace!("Migrating record: {:?}", source_record); + let unwrapped_category = match &source_record.category() { + None => { + warn!( + "Skipping item missing 'category' field, record ({num_record}): \ + {source_record:?}" + ); + migration_result.skipped += 1; + continue; + } + Some(type_) => type_.clone(), + }; + let unwrapped_value = match &source_record.value() { + None => { + warn!( + "Skipping item missing 'value' field, record ({num_record}): {source_record:?}" + ); + migration_result.skipped += 1; + continue; + } + Some(value) => value.clone(), + }; + let unwrapped_tags = match &source_record.tags() { + None => RecordTags::default(), + Some(tags) => tags.clone(), + }; + + let record = Record::builder() + .category(unwrapped_category.parse()?) + .name(source_record.name().to_string()) + .value(unwrapped_value) + .tags(unwrapped_tags) + .build(); + + let migrated_record = match migrate_fn(record) { + Ok(record) => match record { + None => { + warn!("Skipping non-migratable record ({num_record}): {source_record:?}"); + migration_result.skipped += 1; + continue; + } + Some(record) => record, + }, + Err(err) => { + warn!( + "Skipping item due failed item migration, record ({num_record}): \ + {source_record:?}, err: {err}" + ); + migration_result.failed += 1; + continue; + } + }; + + match dest_wallet.add_record(migrated_record.clone()).await { + Err(err) => match err.kind() { + AriesVcxCoreErrorKind::DuplicationWalletRecord => { + trace!( + "Record type: {migrated_record:?} already exists in destination wallet, \ + skipping" + ); + migration_result.duplicated += 1; + continue; + } + _ => { + error!( + "Error adding record {migrated_record:?} to destination wallet: {err:?}" + ); + migration_result.failed += 1; + return Err(err); + } + }, + Ok(()) => { + migration_result.migrated += 1; + } + } + } + warn!("Migration of total {total:?} records completed, result: ${migration_result:?}"); + Ok(migration_result) +} diff --git a/aries/aries_vcx_core/src/wallet/base_wallet/mod.rs b/aries/aries_vcx_core/src/wallet/base_wallet/mod.rs index c29dea9645..6c69388b23 100644 --- a/aries/aries_vcx_core/src/wallet/base_wallet/mod.rs +++ b/aries/aries_vcx_core/src/wallet/base_wallet/mod.rs @@ -1,97 +1,70 @@ use async_trait::async_trait; -use public_key::Key; - -use self::{did_data::DidData, record_category::RecordCategory}; -use super::record_tags::RecordTags; -use crate::{ - errors::error::VcxCoreResult, - wallet::{ - base_wallet::{record::Record, search_filter::SearchFilter}, - structs_io::UnpackMessageOutput, - }, -}; + +use self::{did_wallet::DidWallet, issuer_config::IssuerConfig, record_wallet::RecordWallet}; +use crate::errors::error::VcxCoreResult; pub mod did_data; pub mod did_value; +pub mod did_wallet; +pub mod issuer_config; +pub mod migrate; pub mod record; pub mod record_category; +pub mod record_wallet; pub mod search_filter; -pub trait BaseWallet: RecordWallet + DidWallet + Send + Sync + std::fmt::Debug {} - #[async_trait] -pub trait DidWallet { - async fn create_and_store_my_did( - &self, - seed: Option<&str>, - kdf_method_name: Option<&str>, - ) -> VcxCoreResult; - - async fn key_for_did(&self, did: &str) -> VcxCoreResult; - - async fn key_count(&self) -> VcxCoreResult; - - async fn replace_did_key_start(&self, did: &str, seed: Option<&str>) -> VcxCoreResult; - - async fn replace_did_key_apply(&self, did: &str) -> VcxCoreResult<()>; +pub trait ImportWallet { + async fn import_wallet(&self) -> VcxCoreResult<()>; +} - async fn sign(&self, key: &Key, msg: &[u8]) -> VcxCoreResult>; +#[async_trait] +pub trait ManageWallet { + type ManagedWalletType: BaseWallet; - async fn verify(&self, key: &Key, msg: &[u8], signature: &[u8]) -> VcxCoreResult; + async fn create_wallet(&self) -> VcxCoreResult; - async fn pack_message( - &self, - sender_vk: Option, - receiver_keys: Vec, - msg: &[u8], - ) -> VcxCoreResult>; + async fn open_wallet(&self) -> VcxCoreResult; - async fn unpack_message(&self, msg: &[u8]) -> VcxCoreResult; + async fn delete_wallet(&self) -> VcxCoreResult<()>; } #[async_trait] -pub trait RecordWallet { - async fn add_record(&self, record: Record) -> VcxCoreResult<()>; - - async fn get_record(&self, category: RecordCategory, name: &str) -> VcxCoreResult; - - async fn update_record_tags( - &self, - category: RecordCategory, - name: &str, - new_tags: RecordTags, - ) -> VcxCoreResult<()>; - - async fn update_record_value( - &self, - category: RecordCategory, - name: &str, - new_value: &str, - ) -> VcxCoreResult<()>; - - async fn delete_record(&self, category: RecordCategory, name: &str) -> VcxCoreResult<()>; - - async fn search_record( - &self, - category: RecordCategory, - search_filter: Option, - ) -> VcxCoreResult>; +pub trait BaseWallet: RecordWallet + DidWallet + Send + Sync + std::fmt::Debug { + async fn export_wallet(&self, path: &str, backup_key: &str) -> VcxCoreResult<()>; + + async fn close_wallet(&self) -> VcxCoreResult<()>; + + async fn configure_issuer(&self, key_seed: &str) -> VcxCoreResult { + Ok(IssuerConfig { + institution_did: self + .create_and_store_my_did(Some(key_seed), None) + .await? + .did() + .to_string(), + }) + } } #[cfg(test)] mod tests { + use std::str::FromStr; + use super::BaseWallet; use crate::{ errors::error::AriesVcxCoreErrorKind, wallet::{ - base_wallet::{record_category::RecordCategory, Record}, + base_wallet::{ + did_wallet::DidWallet, record::Record, record_category::RecordCategory, + record_wallet::RecordWallet, + }, record_tags::{RecordTag, RecordTags}, utils::{did_from_key, random_seed}, }, }; #[allow(unused_variables)] - async fn build_test_wallet() -> Box { + async fn build_test_wallet() -> impl BaseWallet { #[cfg(feature = "vdrtools_wallet")] let wallet = { use crate::wallet::indy::tests::dev_setup_indy_wallet; @@ -463,6 +436,42 @@ mod tests { assert_eq!(value, res.value()); assert_eq!(&tags2, res.tags()); } + + #[tokio::test] + async fn record_wallet_should_fetch_all() { + let wallet = build_test_wallet().await; + + wallet + .create_and_store_my_did(Some(&random_seed()), None) + .await + .unwrap(); + + let mut res = wallet.all_records().await.unwrap(); + + if let Some(total_count) = res.total_count().unwrap() { + assert_eq!(2, total_count); + } else { + panic!("expected total count when fetching all records"); + } + + let mut key_count = 0; + let mut did_count = 0; + + while let Some(record) = res.next().await.unwrap() { + if let Some(category) = record.category() { + match RecordCategory::from_str(category).unwrap() { + RecordCategory::Did => did_count += 1, + RecordCategory::Key => key_count += 1, + _ => (), + } + } else { + panic!("expected record to have a category"); + } + } + + assert_eq!(1, key_count); + assert_eq!(1, did_count); + } } #[cfg(test)] @@ -473,10 +482,7 @@ mod compat_tests { indy::tests::dev_setup_indy_wallet, }; - async fn pack_and_unpack_anoncrypt( - sender: Box, - recipient: Box, - ) { + async fn pack_and_unpack_anoncrypt(sender: impl BaseWallet, recipient: impl BaseWallet) { let did_data = recipient.create_and_store_my_did(None, None).await.unwrap(); let msg = "send me"; @@ -491,10 +497,7 @@ mod compat_tests { assert_eq!(msg, unpacked.message); } - async fn pack_and_unpack_authcrypt( - sender: Box, - recipient: Box, - ) { + async fn pack_and_unpack_authcrypt(sender: impl BaseWallet, recipient: impl BaseWallet) { let sender_did_data = sender.create_and_store_my_did(None, None).await.unwrap(); let recipient_did_data = recipient.create_and_store_my_did(None, None).await.unwrap(); diff --git a/aries/aries_vcx_core/src/wallet/base_wallet/record.rs b/aries/aries_vcx_core/src/wallet/base_wallet/record.rs index 3803f83c8f..ab483825c7 100644 --- a/aries/aries_vcx_core/src/wallet/base_wallet/record.rs +++ b/aries/aries_vcx_core/src/wallet/base_wallet/record.rs @@ -1,7 +1,8 @@ +use async_trait::async_trait; use typed_builder::TypedBuilder; use super::record_category::RecordCategory; -use crate::wallet::record_tags::RecordTags; +use crate::{errors::error::VcxCoreResult, wallet::record_tags::RecordTags}; #[derive(Debug, Default, Clone, TypedBuilder)] pub struct Record { @@ -29,3 +30,36 @@ impl Record { &self.tags } } + +#[derive(Debug, Default, Clone, TypedBuilder)] +pub struct PartialRecord { + category: Option, + name: String, + value: Option, + #[builder(default)] + tags: Option, +} + +impl PartialRecord { + pub fn value(&self) -> &Option { + &self.value + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn category(&self) -> &Option { + &self.category + } + + pub fn tags(&self) -> &Option { + &self.tags + } +} + +#[async_trait] +pub trait AllRecords { + fn total_count(&self) -> VcxCoreResult>; + async fn next(&mut self) -> VcxCoreResult>; +} diff --git a/aries/aries_vcx_core/src/wallet/base_wallet/record_category.rs b/aries/aries_vcx_core/src/wallet/base_wallet/record_category.rs index de9b973719..c830106573 100644 --- a/aries/aries_vcx_core/src/wallet/base_wallet/record_category.rs +++ b/aries/aries_vcx_core/src/wallet/base_wallet/record_category.rs @@ -19,6 +19,7 @@ const REV_REG_DEF: &str = "VCX_REV_REG_DEF"; const REV_REG_DEF_PRIV: &str = "VCX_REV_REG_DEF_PRIV"; const DID: &str = "Indy::Did"; const TMP_DID: &str = "Indy::TemporaryDid"; +const KEY: &str = "Indy::Key"; #[derive(Clone, Copy, Debug, Default)] pub enum RecordCategory { @@ -37,6 +38,7 @@ pub enum RecordCategory { RevRegDefPriv, Did, TmpDid, + Key, } impl FromStr for RecordCategory { @@ -58,6 +60,7 @@ impl FromStr for RecordCategory { REV_REG_DEF_PRIV => Ok(RecordCategory::RevRegDefPriv), DID => Ok(RecordCategory::Did), TMP_DID => Ok(RecordCategory::TmpDid), + KEY => Ok(RecordCategory::Key), _ => Err(Self::Err::from_msg( AriesVcxCoreErrorKind::InvalidInput, format!("unknown category: {}", s), @@ -83,6 +86,7 @@ impl Display for RecordCategory { RecordCategory::RevRegDefPriv => REV_REG_DEF_PRIV, RecordCategory::Did => DID, RecordCategory::TmpDid => TMP_DID, + RecordCategory::Key => KEY, }; write!(f, "{}", value) diff --git a/aries/aries_vcx_core/src/wallet/base_wallet/record_wallet.rs b/aries/aries_vcx_core/src/wallet/base_wallet/record_wallet.rs new file mode 100644 index 0000000000..69346b1aab --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/base_wallet/record_wallet.rs @@ -0,0 +1,39 @@ +use async_trait::async_trait; + +use super::{ + record::{AllRecords, Record}, + record_category::RecordCategory, + search_filter::SearchFilter, +}; +use crate::{errors::error::VcxCoreResult, wallet::record_tags::RecordTags}; + +#[async_trait] +pub trait RecordWallet { + async fn all_records(&self) -> VcxCoreResult>; + + async fn add_record(&self, record: Record) -> VcxCoreResult<()>; + + async fn get_record(&self, category: RecordCategory, name: &str) -> VcxCoreResult; + + async fn update_record_tags( + &self, + category: RecordCategory, + name: &str, + new_tags: RecordTags, + ) -> VcxCoreResult<()>; + + async fn update_record_value( + &self, + category: RecordCategory, + name: &str, + new_value: &str, + ) -> VcxCoreResult<()>; + + async fn delete_record(&self, category: RecordCategory, name: &str) -> VcxCoreResult<()>; + + async fn search_record( + &self, + category: RecordCategory, + search_filter: Option, + ) -> VcxCoreResult>; +} diff --git a/aries/aries_vcx_core/src/wallet/constants.rs b/aries/aries_vcx_core/src/wallet/constants.rs deleted file mode 100644 index 3d4c1cd6d9..0000000000 --- a/aries/aries_vcx_core/src/wallet/constants.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub const DID_CATEGORY: &str = "Indy::Did"; -pub const TMP_DID_CATEGORY: &str = "Indy::TemporaryDid"; diff --git a/aries/aries_vcx_core/src/wallet/indy/all_indy_records.rs b/aries/aries_vcx_core/src/wallet/indy/all_indy_records.rs new file mode 100644 index 0000000000..2758d4fcd2 --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/indy/all_indy_records.rs @@ -0,0 +1,30 @@ +use async_trait::async_trait; +use vdrtools::indy_wallet::iterator::WalletIterator; + +use crate::{ + errors::error::VcxCoreResult, + wallet::base_wallet::record::{AllRecords, PartialRecord}, +}; + +pub struct AllIndyRecords { + iterator: WalletIterator, +} + +impl AllIndyRecords { + pub fn new(iterator: WalletIterator) -> Self { + Self { iterator } + } +} + +#[async_trait] +impl AllRecords for AllIndyRecords { + fn total_count(&self) -> VcxCoreResult> { + Ok(self.iterator.get_total_count()?) + } + + async fn next(&mut self) -> VcxCoreResult> { + let item = self.iterator.next().await?; + + Ok(item.map(PartialRecord::from_wallet_record)) + } +} diff --git a/aries/aries_vcx_core/src/wallet/indy/indy_did_wallet.rs b/aries/aries_vcx_core/src/wallet/indy/indy_did_wallet.rs index 9406937f15..2d0b954c48 100644 --- a/aries/aries_vcx_core/src/wallet/indy/indy_did_wallet.rs +++ b/aries/aries_vcx_core/src/wallet/indy/indy_did_wallet.rs @@ -5,7 +5,7 @@ use vdrtools::{DidMethod, DidValue, KeyInfo, Locator, MyDidInfo}; use crate::{ errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind, VcxCoreResult}, wallet::{ - base_wallet::{did_data::DidData, record_category::RecordCategory, DidWallet}, + base_wallet::{did_data::DidData, did_wallet::DidWallet, record_category::RecordCategory}, indy::IndySdkWallet, structs_io::UnpackMessageOutput, }, diff --git a/aries/aries_vcx_core/src/wallet/indy/indy_import_config.rs b/aries/aries_vcx_core/src/wallet/indy/indy_import_config.rs new file mode 100644 index 0000000000..62eeaff81b --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/indy/indy_import_config.rs @@ -0,0 +1,53 @@ +use async_trait::async_trait; +use serde::{Deserialize, Serialize}; +use vdrtools::{types::domain::wallet::default_key_derivation_method, Locator}; + +use super::indy_utils::parse_key_derivation_method; +use crate::{errors::error::VcxCoreResult, wallet::base_wallet::ImportWallet}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct IndyImportConfig { + pub wallet_name: String, + pub wallet_key: String, + pub exported_wallet_path: String, + pub backup_key: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub wallet_key_derivation: Option, +} + +#[async_trait] +impl ImportWallet for IndyImportConfig { + async fn import_wallet(&self) -> VcxCoreResult<()> { + Locator::instance() + .wallet_controller + .import( + vdrtools::types::domain::wallet::Config { + id: self.wallet_name.clone(), + ..Default::default() + }, + vdrtools::types::domain::wallet::Credentials { + key: self.wallet_key.clone(), + key_derivation_method: self + .wallet_key_derivation + .as_deref() + .map(parse_key_derivation_method) + .transpose()? + .unwrap_or_else(default_key_derivation_method), + + rekey: None, + rekey_derivation_method: default_key_derivation_method(), // default value + + storage_credentials: None, // default value + }, + vdrtools::types::domain::wallet::ExportConfig { + key: self.backup_key.clone(), + path: self.exported_wallet_path.clone(), + + key_derivation_method: default_key_derivation_method(), + }, + ) + .await?; + + Ok(()) + } +} diff --git a/aries/aries_vcx_core/src/wallet/indy/indy_record_wallet.rs b/aries/aries_vcx_core/src/wallet/indy/indy_record_wallet.rs index c82e2ebae7..4de08f7c6a 100644 --- a/aries/aries_vcx_core/src/wallet/indy/indy_record_wallet.rs +++ b/aries/aries_vcx_core/src/wallet/indy/indy_record_wallet.rs @@ -2,13 +2,15 @@ use async_trait::async_trait; use indy_api_types::domain::wallet::IndyRecord; use vdrtools::Locator; -use super::{indy_tags::IndyTags, WALLET_OPTIONS}; +use super::{all_indy_records::AllIndyRecords, indy_tags::IndyTags, WALLET_OPTIONS}; use crate::{ errors::error::VcxCoreResult, wallet::{ base_wallet::{ - record::Record, record_category::RecordCategory, search_filter::SearchFilter, - RecordWallet, + record::{AllRecords, Record}, + record_category::RecordCategory, + record_wallet::RecordWallet, + search_filter::SearchFilter, }, indy::IndySdkWallet, record_tags::RecordTags, @@ -17,6 +19,15 @@ use crate::{ #[async_trait] impl RecordWallet for IndySdkWallet { + async fn all_records(&self) -> VcxCoreResult> { + let all = Locator::instance() + .wallet_controller + .get_all(self.get_wallet_handle()) + .await?; + + Ok(Box::new(AllIndyRecords::new(all))) + } + async fn add_record(&self, record: Record) -> VcxCoreResult<()> { let tags_map = if record.tags().is_empty() { None diff --git a/aries/aries_vcx_core/src/wallet/indy/indy_tags.rs b/aries/aries_vcx_core/src/wallet/indy/indy_tags.rs index 71881b7866..ed159686be 100644 --- a/aries/aries_vcx_core/src/wallet/indy/indy_tags.rs +++ b/aries/aries_vcx_core/src/wallet/indy/indy_tags.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use crate::wallet::record_tags::{RecordTag, RecordTags}; -pub(crate) struct IndyTags(HashMap); +pub struct IndyTags(HashMap); impl IndyTags { pub fn new(map: HashMap) -> Self { diff --git a/aries/aries_vcx_core/src/wallet/indy/indy_utils.rs b/aries/aries_vcx_core/src/wallet/indy/indy_utils.rs new file mode 100644 index 0000000000..2843c8ebfa --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/indy/indy_utils.rs @@ -0,0 +1,15 @@ +use indy_api_types::domain::wallet::KeyDerivationMethod; + +use crate::errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind, VcxCoreResult}; + +pub fn parse_key_derivation_method(method: &str) -> VcxCoreResult { + match method { + "RAW" => Ok(KeyDerivationMethod::RAW), + "ARGON2I_MOD" => Ok(KeyDerivationMethod::ARGON2I_MOD), + "ARGON2I_INT" => Ok(KeyDerivationMethod::ARGON2I_INT), + _ => Err(AriesVcxCoreError::from_msg( + AriesVcxCoreErrorKind::InvalidOption, + format!("Unknown derivation method {method}"), + )), + } +} diff --git a/aries/aries_vcx_core/src/wallet/indy/indy_wallet_config.rs b/aries/aries_vcx_core/src/wallet/indy/indy_wallet_config.rs new file mode 100644 index 0000000000..e0f29eda74 --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/indy/indy_wallet_config.rs @@ -0,0 +1,185 @@ +use async_trait::async_trait; +use indy_api_types::{domain::wallet::default_key_derivation_method, errors::IndyErrorKind}; +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; +use vdrtools::Locator; + +use super::indy_utils::parse_key_derivation_method; +use crate::{ + errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind, VcxCoreResult}, + wallet::{base_wallet::ManageWallet, indy::IndySdkWallet}, +}; + +#[derive(Clone, Debug, TypedBuilder, Serialize, Deserialize)] +#[builder(field_defaults(default))] +pub struct IndyWalletConfig { + pub wallet_name: String, + pub wallet_key: String, + pub wallet_key_derivation: String, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(setter(strip_option))] + pub wallet_type: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(setter(strip_option))] + pub storage_config: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(setter(strip_option))] + pub storage_credentials: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(setter(strip_option))] + pub rekey: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(setter(strip_option))] + pub rekey_derivation_method: Option, +} + +#[async_trait] +impl ManageWallet for IndyWalletConfig { + type ManagedWalletType = IndySdkWallet; + + async fn create_wallet(&self) -> VcxCoreResult { + let credentials = vdrtools::types::domain::wallet::Credentials { + key: self.wallet_key.clone(), + key_derivation_method: parse_key_derivation_method(&self.wallet_key_derivation)?, + + rekey: None, + rekey_derivation_method: default_key_derivation_method(), + + storage_credentials: self + .storage_credentials + .as_deref() + .map(serde_json::from_str) + .transpose()?, + }; + + let res = Locator::instance() + .wallet_controller + .create( + vdrtools::types::domain::wallet::Config { + id: self.wallet_name.clone(), + storage_type: self.wallet_type.clone(), + storage_config: self + .storage_config + .as_deref() + .map(serde_json::from_str) + .transpose()?, + cache: None, + }, + credentials, + ) + .await; + + match res { + Ok(()) => self.open_wallet().await, + + Err(err) if err.kind() == IndyErrorKind::WalletAlreadyExists => { + warn!( + "wallet \"{}\" already exists. skipping creation", + self.wallet_name + ); + self.open_wallet().await + } + + Err(err) => Err(AriesVcxCoreError::from_msg( + AriesVcxCoreErrorKind::WalletCreate, + format!("could not create wallet {}: {}", self.wallet_name, err,), + )), + } + } + + async fn open_wallet(&self) -> VcxCoreResult { + let handle = Locator::instance() + .wallet_controller + .open( + vdrtools::types::domain::wallet::Config { + id: self.wallet_name.clone(), + storage_type: self.wallet_type.clone(), + storage_config: self + .storage_config + .as_deref() + .map(serde_json::from_str) + .transpose()?, + cache: None, + }, + vdrtools::types::domain::wallet::Credentials { + key: self.wallet_key.clone(), + key_derivation_method: parse_key_derivation_method( + &self.wallet_key_derivation, + )?, + + rekey: self.rekey.clone(), + rekey_derivation_method: self + .rekey_derivation_method + .as_deref() + .map(parse_key_derivation_method) + .transpose()? + .unwrap_or_else(default_key_derivation_method), + + storage_credentials: self + .storage_credentials + .as_deref() + .map(serde_json::from_str) + .transpose()?, + }, + ) + .await?; + + Ok(IndySdkWallet::new(handle)) + } + + async fn delete_wallet(&self) -> VcxCoreResult<()> { + let credentials = vdrtools::types::domain::wallet::Credentials { + key: self.wallet_key.clone(), + key_derivation_method: parse_key_derivation_method(&self.wallet_key_derivation)?, + + rekey: None, + rekey_derivation_method: default_key_derivation_method(), + + storage_credentials: self + .storage_credentials + .as_deref() + .map(serde_json::from_str) + .transpose()?, + }; + + let res = Locator::instance() + .wallet_controller + .delete( + vdrtools::types::domain::wallet::Config { + id: self.wallet_name.clone(), + storage_type: self.wallet_type.clone(), + storage_config: self + .storage_config + .as_deref() + .map(serde_json::from_str) + .transpose()?, + cache: None, + }, + credentials, + ) + .await; + + match res { + Ok(_) => Ok(()), + + Err(err) if err.kind() == IndyErrorKind::WalletAccessFailed => { + Err(AriesVcxCoreError::from_msg( + AriesVcxCoreErrorKind::WalletAccessFailed, + format!( + "Can not open wallet \"{}\". Invalid key has been provided.", + &self.wallet_name + ), + )) + } + + Err(err) if err.kind() == IndyErrorKind::WalletNotFound => { + Err(AriesVcxCoreError::from_msg( + AriesVcxCoreErrorKind::WalletNotFound, + format!("Wallet \"{}\" not found or unavailable", &self.wallet_name,), + )) + } + + Err(err) => Err(err.into()), + } + } +} diff --git a/aries/aries_vcx_core/src/wallet/indy/indy_wallet_record.rs b/aries/aries_vcx_core/src/wallet/indy/indy_wallet_record.rs new file mode 100644 index 0000000000..65d456421a --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/indy/indy_wallet_record.rs @@ -0,0 +1,29 @@ +use serde::{Deserialize, Serialize}; + +use crate::{errors::error::VcxCoreResult, wallet::base_wallet::record::Record}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct IndyWalletRecord { + id: Option, + #[serde(rename = "type")] + record_type: Option, + pub value: Option, + tags: Option, +} + +impl IndyWalletRecord { + pub fn from_record(record: Record) -> VcxCoreResult { + let tags = if record.tags().is_empty() { + None + } else { + Some(serde_json::to_string(&record.tags())?) + }; + + Ok(Self { + id: Some(record.name().into()), + record_type: Some(record.category().to_string()), + value: Some(record.value().into()), + tags, + }) + } +} diff --git a/aries/aries_vcx_core/src/wallet/indy/internal.rs b/aries/aries_vcx_core/src/wallet/indy/internal.rs deleted file mode 100644 index d75f71db99..0000000000 --- a/aries/aries_vcx_core/src/wallet/indy/internal.rs +++ /dev/null @@ -1,77 +0,0 @@ -use indy_api_types::SearchHandle; -use vdrtools::{Locator, WalletHandle}; - -use crate::errors::error::VcxCoreResult; - -pub async fn delete_wallet_record( - wallet_handle: WalletHandle, - xtype: &str, - id: &str, -) -> VcxCoreResult<()> { - trace!( - "delete_record >>> xtype: {}, id: {}", - secret!(&xtype), - secret!(&id) - ); - - Locator::instance() - .non_secret_controller - .delete_record(wallet_handle, xtype.into(), id.into()) - .await?; - - Ok(()) -} - -// TODO - FUTURE - revert to pub(crate) after libvcx dependency is fixed -pub async fn open_search_wallet( - wallet_handle: WalletHandle, - xtype: &str, - query: &str, - options: &str, -) -> VcxCoreResult { - trace!( - "open_search >>> xtype: {}, query: {}, options: {}", - secret!(&xtype), - query, - options - ); - - let res = Locator::instance() - .non_secret_controller - .open_search(wallet_handle, xtype.into(), query.into(), options.into()) - .await?; - - Ok(res) -} - -// TODO - FUTURE - revert to pub(crate) after libvcx dependency is fixed -pub async fn fetch_next_records_wallet( - wallet_handle: WalletHandle, - search_handle: SearchHandle, - count: usize, -) -> VcxCoreResult { - trace!( - "fetch_next_records >>> search_handle: {:?}, count: {}", - search_handle, - count - ); - - let res = Locator::instance() - .non_secret_controller - .fetch_search_next_records(wallet_handle, search_handle, count) - .await?; - - Ok(res) -} - -// TODO - FUTURE - revert to pub(crate) after libvcx dependency is fixed -pub async fn close_search_wallet(search_handle: SearchHandle) -> VcxCoreResult<()> { - trace!("close_search >>> search_handle: {:?}", search_handle); - - Locator::instance() - .non_secret_controller - .close_search(search_handle) - .await?; - - Ok(()) -} diff --git a/aries/aries_vcx_core/src/wallet/indy/mod.rs b/aries/aries_vcx_core/src/wallet/indy/mod.rs index 2a37f25a80..914a2816aa 100644 --- a/aries/aries_vcx_core/src/wallet/indy/mod.rs +++ b/aries/aries_vcx_core/src/wallet/indy/mod.rs @@ -1,9 +1,9 @@ use std::str::FromStr; -use indy_api_types::domain::wallet::IndyRecord; -use serde::{Deserialize, Serialize}; +use async_trait::async_trait; +use indy_api_types::domain::wallet::{default_key_derivation_method, IndyRecord}; +use serde::Deserialize; use serde_json::Value; -use typed_builder::TypedBuilder; use vdrtools::Locator; use self::indy_tags::IndyTags; @@ -15,11 +15,37 @@ use crate::{ WalletHandle, }; +mod all_indy_records; mod indy_did_wallet; +pub mod indy_import_config; mod indy_record_wallet; mod indy_tags; -pub mod internal; -pub mod wallet; +mod indy_utils; +pub mod indy_wallet_config; +pub mod indy_wallet_record; +mod partial_record; + +impl Record { + pub fn try_from_indy_record(indy_record: IndyRecord) -> VcxCoreResult { + Ok(Record::builder() + .name(indy_record.id) + .category(RecordCategory::from_str(&indy_record.type_)?) + .value(indy_record.value) + .tags(IndyTags::new(indy_record.tags).into_record_tags()) + .build()) + } +} + +impl From for IndyRecord { + fn from(record: Record) -> Self { + Self { + id: record.name().into(), + type_: record.category().to_string(), + value: record.value().into(), + tags: IndyTags::from_record_tags(record.tags().to_owned()).into_inner(), + } + } +} #[derive(Debug)] pub struct IndySdkWallet { @@ -88,121 +114,47 @@ impl IndySdkWallet { } } -#[derive(Clone, Debug, TypedBuilder, Serialize, Deserialize)] -#[builder(field_defaults(default))] -pub struct WalletConfig { - pub wallet_name: String, - pub wallet_key: String, - pub wallet_key_derivation: String, - #[serde(skip_serializing_if = "Option::is_none")] - #[builder(setter(strip_option))] - pub wallet_type: Option, - #[serde(skip_serializing_if = "Option::is_none")] - #[builder(setter(strip_option))] - pub storage_config: Option, - #[serde(skip_serializing_if = "Option::is_none")] - #[builder(setter(strip_option))] - pub storage_credentials: Option, - #[serde(skip_serializing_if = "Option::is_none")] - #[builder(setter(strip_option))] - pub rekey: Option, - #[serde(skip_serializing_if = "Option::is_none")] - #[builder(setter(strip_option))] - pub rekey_derivation_method: Option, -} - -#[derive(Clone, Debug, TypedBuilder, Serialize, Deserialize)] -#[builder(field_defaults(default))] -pub struct IssuerConfig { - pub institution_did: String, -} +const WALLET_OPTIONS: &str = + r#"{"retrieveType": true, "retrieveValue": true, "retrieveTags": true}"#; -#[derive(Clone, Debug, Serialize, Deserialize)] -struct WalletCredentials { - key: String, - #[serde(skip_serializing_if = "Option::is_none")] - rekey: Option, - #[serde(skip_serializing_if = "Option::is_none")] - storage_credentials: Option, - key_derivation_method: String, - #[serde(skip_serializing_if = "Option::is_none")] - rekey_derivation_method: Option, -} +const SEARCH_OPTIONS: &str = r#"{"retrieveType": true, "retrieveValue": true, "retrieveTags": true, "retrieveRecords": true}"#; -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct IndyWalletRecord { - id: Option, - #[serde(rename = "type")] - record_type: Option, - pub value: Option, - tags: Option, -} +#[async_trait] +impl BaseWallet for IndySdkWallet { + async fn export_wallet(&self, path: &str, backup_key: &str) -> VcxCoreResult<()> { + Locator::instance() + .wallet_controller + .export( + self.wallet_handle, + vdrtools::types::domain::wallet::ExportConfig { + key: backup_key.into(), + path: path.into(), -impl IndyWalletRecord { - pub fn from_record(record: Record) -> VcxCoreResult { - let tags = if record.tags().is_empty() { - None - } else { - Some(serde_json::to_string(&record.tags())?) - }; + key_derivation_method: default_key_derivation_method(), + }, + ) + .await?; - Ok(Self { - id: Some(record.name().into()), - record_type: Some(record.category().to_string()), - value: Some(record.value().into()), - tags, - }) + Ok(()) } -} -impl Record { - pub fn try_from_indy_record(indy_record: IndyRecord) -> VcxCoreResult { - Ok(Record::builder() - .name(indy_record.id) - .category(RecordCategory::from_str(&indy_record.type_)?) - .value(indy_record.value) - .tags(IndyTags::new(indy_record.tags).into_record_tags()) - .build()) - } -} + async fn close_wallet(&self) -> VcxCoreResult<()> { + Locator::instance() + .wallet_controller + .close(self.wallet_handle) + .await?; -impl From for IndyRecord { - fn from(record: Record) -> Self { - Self { - id: record.name().into(), - type_: record.category().to_string(), - value: record.value().into(), - tags: IndyTags::from_record_tags(record.tags().to_owned()).into_inner(), - } + Ok(()) } } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct RestoreWalletConfigs { - pub wallet_name: String, - pub wallet_key: String, - pub exported_wallet_path: String, - pub backup_key: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub wallet_key_derivation: Option, -} - -const WALLET_OPTIONS: &str = - r#"{"retrieveType": true, "retrieveValue": true, "retrieveTags": true}"#; - -const SEARCH_OPTIONS: &str = r#"{"retrieveType": true, "retrieveValue": true, "retrieveTags": true, "retrieveRecords": true}"#; - -impl BaseWallet for IndySdkWallet {} - #[cfg(test)] pub mod tests { use super::IndySdkWallet; - use crate::wallet::base_wallet::BaseWallet; - - pub async fn dev_setup_indy_wallet() -> Box { - use crate::wallet::indy::{wallet::create_and_open_wallet, WalletConfig}; + use crate::wallet::{base_wallet::ManageWallet, indy::indy_wallet_config::IndyWalletConfig}; - let config_wallet = WalletConfig { + pub async fn dev_setup_indy_wallet() -> IndySdkWallet { + let config_wallet = IndyWalletConfig { wallet_name: format!("wallet_{}", uuid::Uuid::new_v4()), wallet_key: "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY".into(), wallet_key_derivation: "RAW".into(), @@ -212,8 +164,7 @@ pub mod tests { rekey: None, rekey_derivation_method: None, }; - let wallet_handle = create_and_open_wallet(&config_wallet).await.unwrap(); - Box::new(IndySdkWallet::new(wallet_handle)) + config_wallet.create_wallet().await.unwrap() } } diff --git a/aries/aries_vcx_core/src/wallet/indy/partial_record.rs b/aries/aries_vcx_core/src/wallet/indy/partial_record.rs new file mode 100644 index 0000000000..5c81dd4dda --- /dev/null +++ b/aries/aries_vcx_core/src/wallet/indy/partial_record.rs @@ -0,0 +1,21 @@ +use vdrtools::WalletRecord; + +use super::indy_tags::IndyTags; +use crate::wallet::base_wallet::record::PartialRecord; + +impl PartialRecord { + pub fn from_wallet_record(wallet_record: WalletRecord) -> Self { + let name = wallet_record.get_id().into(); + let category = wallet_record.get_type(); + let value = wallet_record.get_value(); + + let found_tags = wallet_record.get_tags(); + + Self::builder() + .name(name) + .category(category.map(Into::into)) + .value(value.map(Into::into)) + .tags(found_tags.map(|tags| IndyTags::new(tags.clone()).into_record_tags())) + .build() + } +} diff --git a/aries/aries_vcx_core/src/wallet/indy/wallet.rs b/aries/aries_vcx_core/src/wallet/indy/wallet.rs deleted file mode 100644 index 00426d85cf..0000000000 --- a/aries/aries_vcx_core/src/wallet/indy/wallet.rs +++ /dev/null @@ -1,311 +0,0 @@ -use vdrtools::{ - types::{ - domain::wallet::{default_key_derivation_method, KeyDerivationMethod}, - errors::IndyErrorKind, - }, - DidMethod, Locator, MyDidInfo, WalletHandle, -}; - -use crate::{ - errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind, VcxCoreResult}, - wallet::indy::{IssuerConfig, RestoreWalletConfigs, WalletConfig}, -}; - -pub async fn open_wallet(wallet_config: &WalletConfig) -> VcxCoreResult { - trace!("open_as_main_wallet >>> {}", &wallet_config.wallet_name); - - Locator::instance() - .wallet_controller - .open( - vdrtools::types::domain::wallet::Config { - id: wallet_config.wallet_name.clone(), - storage_type: wallet_config.wallet_type.clone(), - storage_config: wallet_config - .storage_config - .as_deref() - .map(serde_json::from_str) - .transpose()?, - cache: None, - }, - vdrtools::types::domain::wallet::Credentials { - key: wallet_config.wallet_key.clone(), - key_derivation_method: parse_key_derivation_method( - &wallet_config.wallet_key_derivation, - )?, - - rekey: wallet_config.rekey.clone(), - rekey_derivation_method: wallet_config - .rekey_derivation_method - .as_deref() - .map(parse_key_derivation_method) - .transpose()? - .unwrap_or_else(default_key_derivation_method), - - storage_credentials: wallet_config - .storage_credentials - .as_deref() - .map(serde_json::from_str) - .transpose()?, - }, - ) - .await - .map_err(From::from) -} - -fn parse_key_derivation_method(method: &str) -> Result { - match method { - "RAW" => Ok(KeyDerivationMethod::RAW), - "ARGON2I_MOD" => Ok(KeyDerivationMethod::ARGON2I_MOD), - "ARGON2I_INT" => Ok(KeyDerivationMethod::ARGON2I_INT), - _ => Err(AriesVcxCoreError::from_msg( - AriesVcxCoreErrorKind::InvalidOption, - format!("Unknown derivation method {method}"), - )), - } -} - -pub async fn create_indy_wallet(wallet_config: &WalletConfig) -> VcxCoreResult<()> { - trace!("create_wallet >>> {}", &wallet_config.wallet_name); - - let credentials = vdrtools::types::domain::wallet::Credentials { - key: wallet_config.wallet_key.clone(), - key_derivation_method: parse_key_derivation_method(&wallet_config.wallet_key_derivation)?, - - rekey: None, - rekey_derivation_method: default_key_derivation_method(), - - storage_credentials: wallet_config - .storage_credentials - .as_deref() - .map(serde_json::from_str) - .transpose()?, - }; - - trace!("Credentials: {:?}", credentials); - - let res = Locator::instance() - .wallet_controller - .create( - vdrtools::types::domain::wallet::Config { - id: wallet_config.wallet_name.clone(), - storage_type: wallet_config.wallet_type.clone(), - storage_config: wallet_config - .storage_config - .as_deref() - .map(serde_json::from_str) - .transpose()?, - cache: None, - }, - credentials, - ) - .await; - - match res { - Ok(()) => Ok(()), - - Err(err) if err.kind() == IndyErrorKind::WalletAlreadyExists => { - warn!( - "wallet \"{}\" already exists. skipping creation", - wallet_config.wallet_name - ); - Ok(()) - } - - Err(err) => Err(AriesVcxCoreError::from_msg( - AriesVcxCoreErrorKind::WalletCreate, - format!( - "could not create wallet {}: {}", - wallet_config.wallet_name, err, - ), - )), - } -} - -pub async fn delete_wallet(wallet_config: &WalletConfig) -> VcxCoreResult<()> { - trace!( - "delete_wallet >>> wallet_name: {}", - &wallet_config.wallet_name - ); - - let credentials = vdrtools::types::domain::wallet::Credentials { - key: wallet_config.wallet_key.clone(), - key_derivation_method: parse_key_derivation_method(&wallet_config.wallet_key_derivation)?, - - rekey: None, - rekey_derivation_method: default_key_derivation_method(), - - storage_credentials: wallet_config - .storage_credentials - .as_deref() - .map(serde_json::from_str) - .transpose()?, - }; - - trace!("Credentials: {:?}", credentials); - - let res = Locator::instance() - .wallet_controller - .delete( - vdrtools::types::domain::wallet::Config { - id: wallet_config.wallet_name.clone(), - storage_type: wallet_config.wallet_type.clone(), - storage_config: wallet_config - .storage_config - .as_deref() - .map(serde_json::from_str) - .transpose()?, - cache: None, - }, - credentials, - ) - .await; - - match res { - Ok(_) => Ok(()), - - Err(err) if err.kind() == IndyErrorKind::WalletAccessFailed => { - Err(AriesVcxCoreError::from_msg( - AriesVcxCoreErrorKind::WalletAccessFailed, - format!( - "Can not open wallet \"{}\". Invalid key has been provided.", - &wallet_config.wallet_name - ), - )) - } - - Err(err) if err.kind() == IndyErrorKind::WalletNotFound => { - Err(AriesVcxCoreError::from_msg( - AriesVcxCoreErrorKind::WalletNotFound, - format!( - "Wallet \"{}\" not found or unavailable", - &wallet_config.wallet_name, - ), - )) - } - - Err(err) => Err(err.into()), - } -} - -pub async fn import(restore_config: &RestoreWalletConfigs) -> VcxCoreResult<()> { - trace!( - "import >>> wallet: {} exported_wallet_path: {}", - restore_config.wallet_name, - restore_config.exported_wallet_path - ); - - Locator::instance() - .wallet_controller - .import( - vdrtools::types::domain::wallet::Config { - id: restore_config.wallet_name.clone(), - ..Default::default() - }, - vdrtools::types::domain::wallet::Credentials { - key: restore_config.wallet_key.clone(), - key_derivation_method: restore_config - .wallet_key_derivation - .as_deref() - .map(parse_key_derivation_method) - .transpose()? - .unwrap_or_else(default_key_derivation_method), - - rekey: None, - rekey_derivation_method: default_key_derivation_method(), // default value - - storage_credentials: None, // default value - }, - vdrtools::types::domain::wallet::ExportConfig { - key: restore_config.backup_key.clone(), - path: restore_config.exported_wallet_path.clone(), - - key_derivation_method: default_key_derivation_method(), - }, - ) - .await?; - - Ok(()) -} - -// TODO - FUTURE - can this be moved externally - move to a generic setup util? -pub async fn wallet_configure_issuer( - wallet_handle: WalletHandle, - key_seed: &str, -) -> VcxCoreResult { - let (institution_did, _vk) = - create_and_store_my_did(wallet_handle, Some(key_seed), None).await?; - - Ok(IssuerConfig { institution_did }) -} - -pub async fn export_wallet( - wallet_handle: WalletHandle, - path: &str, - backup_key: &str, -) -> VcxCoreResult<()> { - trace!( - "export >>> wallet_handle: {:?}, path: {:?}, backup_key: ****", - wallet_handle, - path - ); - - Locator::instance() - .wallet_controller - .export( - wallet_handle, - vdrtools::types::domain::wallet::ExportConfig { - key: backup_key.into(), - path: path.into(), - - key_derivation_method: default_key_derivation_method(), - }, - ) - .await?; - - Ok(()) -} - -pub async fn create_and_open_wallet(wallet_config: &WalletConfig) -> VcxCoreResult { - create_indy_wallet(wallet_config).await?; - - let handle = open_wallet(wallet_config).await?; - - Ok(handle) -} - -pub async fn close_wallet(wallet_handle: WalletHandle) -> VcxCoreResult<()> { - trace!("close_wallet >>>"); - - Locator::instance() - .wallet_controller - .close(wallet_handle) - .await?; - - Ok(()) -} - -pub async fn create_and_store_my_did( - wallet_handle: WalletHandle, - seed: Option<&str>, - method_name: Option<&str>, -) -> VcxCoreResult<(String, String)> { - trace!( - "create_and_store_my_did >>> seed: {:?}, method_name: {:?}", - seed, - method_name - ); - - let res = Locator::instance() - .did_controller - .create_and_store_my_did( - wallet_handle, - MyDidInfo { - method_name: method_name.map(|m| DidMethod(m.into())), - seed: seed.map(ToOwned::to_owned), - ..MyDidInfo::default() - }, - ) - .await?; - - Ok(res) -} diff --git a/aries/misc/legacy/libvcx_core/Cargo.toml b/aries/misc/legacy/libvcx_core/Cargo.toml index f6f6e2b8d1..500356864d 100644 --- a/aries/misc/legacy/libvcx_core/Cargo.toml +++ b/aries/misc/legacy/libvcx_core/Cargo.toml @@ -7,6 +7,8 @@ edition.workspace = true [features] fatal_warnings = [] +askar_wallet = ["aries_vcx/askar_wallet", "aries_vcx_core/askar_wallet"] +vdrtools_wallet = ["aries_vcx/vdrtools_wallet", "aries_vcx_core/vdrtools_wallet"] [dependencies] num-traits = "0.2.0" @@ -23,7 +25,7 @@ serde = "1.0.97" serde_json = "1.0.40" serde_derive = "1.0.97" futures = { version = "0.3", default-features = false } -aries_vcx = { path = "../../../aries_vcx", features = ["credx", "vdrtools_wallet"] } +aries_vcx = { path = "../../../aries_vcx", features = ["credx"] } aries_vcx_core = { path = "../../../aries_vcx_core" } anoncreds_types = { path = "../../../../aries/misc/anoncreds_types" } diddoc_legacy = { path = "../diddoc_legacy" } diff --git a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/agency_client.rs b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/agency_client.rs index fdb05c9dcc..7bbb54608c 100644 --- a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/agency_client.rs +++ b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/agency_client.rs @@ -10,7 +10,7 @@ use aries_vcx::agency_client::{ MessageStatusCode, }; use aries_vcx_core::wallet::{ - agency_client_wallet::ToBaseAgencyClientWallet, base_wallet::DidWallet, + agency_client_wallet::ToBaseAgencyClientWallet, base_wallet::did_wallet::DidWallet, }; use super::profile::get_main_wallet; diff --git a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/ledger.rs b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/ledger.rs index a0972f2079..75a7646b09 100644 --- a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/ledger.rs +++ b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/ledger.rs @@ -205,7 +205,7 @@ mod tests { use crate::api_vcx::api_global::{ ledger::{get_taa_configuration, ledger_get_txn_author_agreement, set_taa_configuration}, pool::{open_main_pool, LibvcxLedgerConfig}, - wallet::test_utils::_create_and_open_wallet, + wallet::wallet::test_utils::_create_and_open_wallet, }; #[tokio::test] diff --git a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/pool.rs b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/pool.rs index 1d3d7f4a6e..ec5d3bae89 100644 --- a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/pool.rs +++ b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/pool.rs @@ -159,7 +159,7 @@ mod tests { api_vcx::api_global::{ pool::{close_main_pool, open_main_pool, reset_ledger_components, LibvcxLedgerConfig}, profile::get_main_ledger_read, - wallet::{close_main_wallet, test_utils::_create_and_open_wallet}, + wallet::wallet::{close_main_wallet, test_utils::_create_and_open_wallet}, }, errors::error::LibvcxErrorKind, }; diff --git a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/profile.rs b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/profile.rs index 6863338194..6a711e8b50 100644 --- a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/profile.rs +++ b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/profile.rs @@ -7,35 +7,83 @@ use aries_vcx::{ ledger::base_ledger::{IndyLedgerRead, IndyLedgerWrite}, }, }; +#[cfg(feature = "askar_wallet")] +use aries_vcx_core::wallet::askar::AskarWallet; +#[cfg(feature = "vdrtools_wallet")] +use aries_vcx_core::wallet::indy::IndySdkWallet; use aries_vcx_core::{ ledger::base_ledger::{ AnoncredsLedgerRead, AnoncredsLedgerWrite, TaaConfigurator, TxnAuthrAgrmtOptions, }, - wallet::indy::IndySdkWallet, + wallet::base_wallet::BaseWallet, }; +#[cfg(feature = "askar_wallet")] +use super::wallet::askar::GLOBAL_ASKAR_WALLET; +#[cfg(feature = "vdrtools_wallet")] +use super::wallet::indy::GLOBAL_INDY_WALLET; use crate::{ api_vcx::api_global::{ pool::{GLOBAL_LEDGER_INDY_READ, GLOBAL_LEDGER_INDY_WRITE}, - wallet::{GLOBAL_BASE_ANONCREDS, GLOBAL_BASE_WALLET}, + wallet::GLOBAL_BASE_ANONCREDS, }, errors::error::{LibvcxError, LibvcxErrorKind, LibvcxResult}, }; -pub fn try_get_main_wallet() -> LibvcxResult>> { - let base_wallet = GLOBAL_BASE_WALLET.read()?; +#[cfg(feature = "vdrtools_wallet")] +pub fn try_get_main_indy_wallet() -> LibvcxResult>> { + let base_wallet = GLOBAL_INDY_WALLET.read()?; base_wallet.as_ref().cloned().map(Some).ok_or_else(|| { LibvcxError::from_msg(LibvcxErrorKind::NotReady, "Wallet is not initialized") }) } -pub fn get_main_wallet() -> LibvcxResult> { - let base_wallet = GLOBAL_BASE_WALLET.read()?; +#[cfg(feature = "askar_wallet")] +pub fn try_get_main_askar_wallet() -> LibvcxResult>> { + let base_wallet = GLOBAL_ASKAR_WALLET.read()?; + base_wallet.as_ref().cloned().map(Some).ok_or_else(|| { + LibvcxError::from_msg(LibvcxErrorKind::NotReady, "Wallet is not initialized") + }) +} + +#[allow(unused_variables)] +pub fn try_get_main_wallet() -> LibvcxResult>> { + #[cfg(feature = "vdrtools_wallet")] + let wallet = try_get_main_indy_wallet()?; + + #[cfg(feature = "askar_wallet")] + let wallet = try_get_main_askar_wallet()?; + + Ok(wallet) +} + +#[cfg(feature = "askar_wallet")] +pub fn get_main_askar_wallet() -> LibvcxResult> { + let base_wallet = GLOBAL_ASKAR_WALLET.read()?; base_wallet.as_ref().cloned().ok_or_else(|| { LibvcxError::from_msg(LibvcxErrorKind::NotReady, "Wallet is not initialized") }) } +#[cfg(feature = "vdrtools_wallet")] +pub fn get_main_indy_wallet() -> LibvcxResult> { + let base_wallet = GLOBAL_INDY_WALLET.read()?; + base_wallet.as_ref().cloned().ok_or_else(|| { + LibvcxError::from_msg(LibvcxErrorKind::NotReady, "Wallet is not initialized") + }) +} + +#[allow(unused_variables)] +pub fn get_main_wallet() -> LibvcxResult> { + #[cfg(feature = "vdrtools_wallet")] + let wallet = get_main_indy_wallet()?; + + #[cfg(feature = "askar_wallet")] + let wallet = get_main_askar_wallet()?; + + Ok(wallet) +} + pub fn get_main_anoncreds() -> LibvcxResult> { let anoncreds = GLOBAL_BASE_ANONCREDS.read()?; anoncreds.as_ref().cloned().ok_or_else(|| { diff --git a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/state.rs b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/state.rs index 075ecadfc9..3a59fc9549 100644 --- a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/state.rs +++ b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/state.rs @@ -1,7 +1,7 @@ use crate::api_vcx::api_global::{ agency_client::reset_main_agency_client, pool::{close_main_pool, reset_ledger_components}, - wallet::close_main_wallet, + wallet::wallet::close_main_wallet, }; pub fn state_vcx_shutdown() { diff --git a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet.rs b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet.rs deleted file mode 100644 index 2e5ad2de2d..0000000000 --- a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet.rs +++ /dev/null @@ -1,765 +0,0 @@ -use std::{ - str::FromStr, - sync::{Arc, RwLock}, -}; - -use aries_vcx::{ - aries_vcx_core::{ - anoncreds::{base_anoncreds::BaseAnonCreds, credx_anoncreds::IndyCredxAnonCreds}, - wallet, - wallet::{ - indy::{ - internal::{close_search_wallet, fetch_next_records_wallet, open_search_wallet}, - wallet::{close_wallet, create_indy_wallet, import, open_wallet}, - IndySdkWallet, IssuerConfig, RestoreWalletConfigs, WalletConfig, - }, - structs_io::UnpackMessageOutput, - }, - SearchHandle, WalletHandle, - }, - global::settings::DEFAULT_LINK_SECRET_ALIAS, - protocols::mediated_connection::pairwise_info::PairwiseInfo, -}; -use aries_vcx_core::wallet::{ - base_wallet::{record::Record, record_category::RecordCategory, DidWallet, RecordWallet}, - indy::IndyWalletRecord, - record_tags::RecordTags, -}; -use futures::FutureExt; -use public_key::{Key, KeyType}; - -use crate::{ - api_vcx::api_global::profile::{ - get_main_anoncreds, get_main_ledger_write, get_main_wallet, try_get_main_wallet, - }, - errors::{ - error::{LibvcxError, LibvcxErrorKind, LibvcxResult}, - mapping_from_ariesvcx::map_ariesvcx_result, - mapping_from_ariesvcxcore::map_ariesvcx_core_result, - }, -}; - -pub static GLOBAL_BASE_WALLET: RwLock>> = RwLock::new(None); -pub static GLOBAL_BASE_ANONCREDS: RwLock>> = RwLock::new(None); - -pub fn get_main_wallet_handle() -> LibvcxResult { - get_main_wallet().map(|wallet| wallet.get_wallet_handle()) -} - -pub async fn export_main_wallet(path: &str, backup_key: &str) -> LibvcxResult<()> { - let wallet_handle = get_main_wallet_handle()?; - map_ariesvcx_core_result( - wallet::indy::wallet::export_wallet(wallet_handle, path, backup_key).await, - ) -} - -fn build_component_base_wallet(wallet_handle: WalletHandle) -> Arc { - Arc::new(IndySdkWallet::new(wallet_handle)) -} - -fn setup_global_wallet(wallet_handle: WalletHandle) -> LibvcxResult<()> { - // new way - let base_wallet_impl = build_component_base_wallet(wallet_handle); - let mut b_wallet = GLOBAL_BASE_WALLET.write()?; - *b_wallet = Some(base_wallet_impl); - // anoncreds - let base_anoncreds_impl = Arc::new(IndyCredxAnonCreds); - let mut b_anoncreds = GLOBAL_BASE_ANONCREDS.write()?; - *b_anoncreds = Some(base_anoncreds_impl); - Ok(()) -} - -pub fn setup_wallet(handle: WalletHandle) -> LibvcxResult<()> { - setup_global_wallet(handle) -} - -pub async fn open_as_main_wallet(wallet_config: &WalletConfig) -> LibvcxResult { - let handle = wallet::indy::wallet::open_wallet(wallet_config).await?; - setup_wallet(handle)?; - Ok(handle) -} - -pub async fn create_and_open_as_main_wallet( - wallet_config: &WalletConfig, -) -> LibvcxResult { - let handle = wallet::indy::wallet::create_and_open_wallet(wallet_config).await?; - setup_wallet(handle)?; - Ok(handle) -} - -pub async fn close_main_wallet() -> LibvcxResult<()> { - let wallet = try_get_main_wallet()?; - match wallet { - None => { - warn!("Skipping wallet close, no global wallet component available.") - } - Some(wallet) => { - wallet::indy::wallet::close_wallet(wallet.get_wallet_handle()).await?; - let mut b_wallet = GLOBAL_BASE_WALLET.write()?; - *b_wallet = None; - } - } - Ok(()) -} - -pub async fn create_main_wallet(config: &WalletConfig) -> LibvcxResult<()> { - let wallet_handle = create_and_open_as_main_wallet(config).await?; - trace!("Created wallet with handle {:?}", wallet_handle); - let wallet = get_main_wallet()?; - - // If MS is already in wallet then just continue - get_main_anoncreds()? - .prover_create_link_secret(wallet.as_ref(), &DEFAULT_LINK_SECRET_ALIAS.to_string()) - .await - .ok(); - - close_main_wallet().await?; - Ok(()) -} - -pub async fn key_for_local_did(did: &str) -> LibvcxResult { - let wallet = get_main_wallet()?; - - map_ariesvcx_core_result(wallet.key_for_did(did).await.map(|key| key.base58())) -} - -pub async fn wallet_sign(vk: &str, data_raw: &[u8]) -> LibvcxResult> { - let wallet = get_main_wallet()?; - - let verkey = Key::from_base58(vk, KeyType::Ed25519)?; - map_ariesvcx_core_result(wallet.sign(&verkey, data_raw).await) -} - -pub async fn wallet_verify(vk: &str, msg: &[u8], signature: &[u8]) -> LibvcxResult { - let wallet = get_main_wallet()?; - - let verkey = Key::from_base58(vk, KeyType::Ed25519)?; - map_ariesvcx_core_result(wallet.verify(&verkey, msg, signature).await) -} - -pub async fn replace_did_keys_start(did: &str) -> LibvcxResult { - let wallet = get_main_wallet()?; - - map_ariesvcx_core_result( - wallet - .replace_did_key_start(did, None) - .await - .map(|key| key.base58()), - ) -} - -pub async fn rotate_verkey_apply(did: &str, temp_vk: &str) -> LibvcxResult<()> { - map_ariesvcx_result( - aries_vcx::common::keys::rotate_verkey_apply( - get_main_wallet()?.as_ref(), - get_main_ledger_write()?.as_ref(), - &did.parse()?, - temp_vk, - ) - .await, - ) -} - -pub async fn wallet_unpack_message(payload: &[u8]) -> LibvcxResult { - let wallet = get_main_wallet()?; - map_ariesvcx_core_result(wallet.unpack_message(payload).await) -} - -pub async fn wallet_create_and_store_did(seed: Option<&str>) -> LibvcxResult { - let wallet = get_main_wallet()?; - let did_data = wallet.create_and_store_my_did(seed, None).await?; - Ok(PairwiseInfo { - pw_did: did_data.did().into(), - pw_vk: did_data.verkey().base58(), - }) -} - -pub async fn wallet_configure_issuer(enterprise_seed: &str) -> LibvcxResult { - // TODO - future - use profile wallet to stop indy dependency - let wallet = get_main_wallet_handle()?; - map_ariesvcx_core_result( - wallet::indy::wallet::wallet_configure_issuer(wallet, enterprise_seed).await, - ) -} - -pub async fn wallet_add_wallet_record( - type_: &str, - id: &str, - value: &str, - option: Option<&str>, -) -> LibvcxResult<()> { - let wallet = get_main_wallet()?; - let tags: Option = option.map(serde_json::from_str).transpose()?; - - let record = if let Some(record_tags) = tags { - Record::builder() - .name(id.into()) - .category(RecordCategory::from_str(type_)?) - .value(value.into()) - .tags(record_tags) - .build() - } else { - Record::builder() - .name(id.into()) - .category(RecordCategory::from_str(type_)?) - .value(value.into()) - .build() - }; - - map_ariesvcx_core_result(wallet.add_record(record).await) -} - -pub async fn wallet_update_wallet_record_value( - xtype: &str, - id: &str, - value: &str, -) -> LibvcxResult<()> { - let wallet = get_main_wallet()?; - map_ariesvcx_core_result( - wallet - .update_record_value(RecordCategory::from_str(xtype)?, id, value) - .await, - ) -} - -pub async fn wallet_update_wallet_record_tags( - xtype: &str, - id: &str, - tags_json: &str, -) -> LibvcxResult<()> { - let wallet = get_main_wallet()?; - let tags: RecordTags = serde_json::from_str(tags_json)?; - map_ariesvcx_core_result( - wallet - .update_record_tags(RecordCategory::from_str(xtype)?, id, tags) - .await, - ) -} - -pub async fn wallet_add_wallet_record_tags( - xtype: &str, - id: &str, - tags_json: &str, -) -> LibvcxResult<()> { - let wallet = get_main_wallet()?; - let record = wallet - .get_record(RecordCategory::from_str(xtype)?, id) - .await?; - - let tags = { - let mut tags: RecordTags = serde_json::from_str(tags_json)?; - tags.merge(record.tags().clone()); - tags - }; - - map_ariesvcx_core_result( - wallet - .update_record_tags(RecordCategory::from_str(xtype)?, id, tags) - .await, - ) -} - -pub async fn wallet_delete_wallet_record_tags( - xtype: &str, - id: &str, - tags_json: &str, -) -> LibvcxResult<()> { - let wallet = get_main_wallet()?; - let tags: RecordTags = serde_json::from_str(tags_json)?; - - let record = wallet - .get_record(RecordCategory::from_str(xtype)?, id) - .await?; - - let mut found_tags = record.tags().clone(); - for key in tags { - found_tags.remove(key); - } - - map_ariesvcx_core_result( - wallet - .update_record_tags(RecordCategory::from_str(xtype)?, id, found_tags) - .await, - ) -} - -pub async fn wallet_get_wallet_record( - xtype: &str, - id: &str, - _options: &str, -) -> LibvcxResult { - let wallet = get_main_wallet()?; - - map_ariesvcx_result( - wallet - .get_record(RecordCategory::from_str(xtype)?, id) - .map(|res| { - let wallet_record = IndyWalletRecord::from_record(res?)?; - - Ok(serde_json::to_string(&wallet_record)?) - }) - .await, - ) -} - -pub async fn wallet_delete_wallet_record(xtype: &str, id: &str) -> LibvcxResult<()> { - let wallet = get_main_wallet()?; - map_ariesvcx_core_result( - wallet - .delete_record(RecordCategory::from_str(xtype)?, id) - .await, - ) -} - -pub async fn wallet_open_search_wallet( - xtype: &str, - query_json: &str, - options_json: &str, -) -> LibvcxResult { - // TODO - future - use profile wallet to stop binding to indy - let wallet_handle = get_main_wallet_handle()?; - map_ariesvcx_core_result( - open_search_wallet(wallet_handle, xtype, query_json, options_json).await, - ) -} - -pub async fn wallet_close_search_wallet(wallet_search_handle: SearchHandle) -> LibvcxResult<()> { - map_ariesvcx_core_result(close_search_wallet(wallet_search_handle).await) -} - -pub async fn wallet_fetch_next_records_wallet( - wallet_search_handle: SearchHandle, - count: usize, -) -> LibvcxResult { - // TODO - future - use profile wallet to stop binding to indy - let wallet_handle = get_main_wallet_handle()?; - map_ariesvcx_core_result( - fetch_next_records_wallet(wallet_handle, wallet_search_handle, count).await, - ) -} - -pub async fn wallet_import(config: &RestoreWalletConfigs) -> LibvcxResult<()> { - map_ariesvcx_core_result(import(config).await) -} - -pub async fn wallet_migrate(wallet_config: &WalletConfig) -> LibvcxResult<()> { - let src_wallet_handle = get_main_wallet_handle()?; - info!("Assuring target wallet exists."); - create_indy_wallet(wallet_config).await?; - info!("Opening target wallet."); - let dest_wallet_handle = open_wallet(wallet_config).await?; - info!("Target wallet is ready."); - - let migration_res = wallet_migrator::migrate_wallet( - src_wallet_handle, - dest_wallet_handle, - wallet_migrator::vdrtools2credx::migrate_any_record, - ) - .await; - - info!("Closing source and target wallets"); - close_wallet(src_wallet_handle).await.ok(); - close_wallet(dest_wallet_handle).await.ok(); - - migration_res.map_err(|e| LibvcxError::from_msg(LibvcxErrorKind::WalletMigrationFailed, e)) -} - -#[cfg(test)] -pub mod test_utils { - use ::test_utils::devsetup::TempFile; - use aries_vcx::{ - aries_vcx_core::wallet::indy::WalletConfig, - global::settings::{DEFAULT_WALLET_BACKUP_KEY, DEFAULT_WALLET_KEY, WALLET_KDF_RAW}, - }; - use aries_vcx_core::wallet::base_wallet::{ - record::Record, record_category::RecordCategory, DidWallet, RecordWallet, - }; - - use crate::{ - api_vcx::api_global::{ - profile::get_main_wallet, - wallet::{ - close_main_wallet, create_and_open_as_main_wallet, create_main_wallet, - export_main_wallet, open_as_main_wallet, - }, - }, - errors::error::LibvcxResult, - }; - - pub async fn _create_main_wallet_and_its_backup() -> (TempFile, String, WalletConfig) { - let wallet_name = &format!("export_test_wallet_{}", uuid::Uuid::new_v4()); - - let export_file = TempFile::prepare_path(wallet_name); - - let wallet_config = WalletConfig { - wallet_name: wallet_name.into(), - wallet_key: DEFAULT_WALLET_KEY.into(), - wallet_key_derivation: WALLET_KDF_RAW.into(), - wallet_type: None, - storage_config: None, - storage_credentials: None, - rekey: None, - rekey_derivation_method: None, - }; - create_and_open_as_main_wallet(&wallet_config) - .await - .unwrap(); - let wallet = get_main_wallet().unwrap(); - wallet.create_and_store_my_did(None, None).await.unwrap(); - - let new_record = Record::builder() - .name("id1".to_owned()) - .category(RecordCategory::default()) - .value("value1".to_owned()) - .build(); - - wallet.add_record(new_record).await.unwrap(); - export_main_wallet(&export_file.path, DEFAULT_WALLET_BACKUP_KEY) - .await - .unwrap(); - - close_main_wallet().await.unwrap(); - - // todo: import and verify - (export_file, wallet_name.to_string(), wallet_config) - } - - pub async fn _create_wallet() -> LibvcxResult { - let wallet_name = format!("test_create_wallet_{}", uuid::Uuid::new_v4()); - let config_wallet: WalletConfig = serde_json::from_value(json!({ - "wallet_name": wallet_name, - "wallet_key": DEFAULT_WALLET_KEY, - "wallet_key_derivation": WALLET_KDF_RAW - }))?; - create_main_wallet(&config_wallet).await?; - Ok(config_wallet) - } - - pub async fn _create_and_open_wallet() -> LibvcxResult { - let config_wallet = _create_wallet().await?; - open_as_main_wallet(&config_wallet).await?; - Ok(config_wallet) - } -} - -#[cfg(test)] -mod tests { - use aries_vcx::{ - aries_vcx_core::wallet::indy::{ - wallet::delete_wallet, IndyWalletRecord, RestoreWalletConfigs, WalletConfig, - }, - global::settings::{DEFAULT_WALLET_BACKUP_KEY, DEFAULT_WALLET_KEY, WALLET_KDF_RAW}, - }; - use aries_vcx_core::wallet::base_wallet::record_category::RecordCategory; - use test_utils::devsetup::{SetupMocks, TempFile}; - - use crate::{ - api_vcx::api_global::wallet::{ - close_main_wallet, create_and_open_as_main_wallet, create_main_wallet, - export_main_wallet, open_as_main_wallet, - test_utils::{_create_and_open_wallet, _create_main_wallet_and_its_backup}, - wallet_add_wallet_record, wallet_delete_wallet_record, wallet_get_wallet_record, - wallet_import, wallet_update_wallet_record_value, - }, - errors::error::{LibvcxErrorKind, LibvcxResult}, - }; - - #[tokio::test] - async fn test_wallet_migrate() { - let wallet_name = format!("test_create_wallet_{}", uuid::Uuid::new_v4()); - let config: WalletConfig = serde_json::from_value(json!({ - "wallet_name": wallet_name, - "wallet_key": DEFAULT_WALLET_KEY, - "wallet_key_derivation": WALLET_KDF_RAW - })) - .unwrap(); - - create_and_open_as_main_wallet(&config).await.unwrap(); - - let wallet_name = format!("test_migrate_wallet_{}", uuid::Uuid::new_v4()); - let new_config: WalletConfig = serde_json::from_value(json!({ - "wallet_name": wallet_name, - "wallet_key": DEFAULT_WALLET_KEY, - "wallet_key_derivation": WALLET_KDF_RAW - })) - .unwrap(); - - super::wallet_migrate(&new_config).await.unwrap(); - } - - #[tokio::test] - async fn test_wallet_create() { - let _setup = SetupMocks::init(); - - let wallet_name = format!("test_create_wallet_{}", uuid::Uuid::new_v4()); - let config: WalletConfig = serde_json::from_value(json!({ - "wallet_name": wallet_name, - "wallet_key": DEFAULT_WALLET_KEY, - "wallet_key_derivation": WALLET_KDF_RAW - })) - .unwrap(); - - create_main_wallet(&config).await.unwrap(); - } - - #[tokio::test] - async fn test_wallet_record_add_with_tag() { - _create_and_open_wallet().await.unwrap(); - - let xtype = RecordCategory::default().to_string(); - let id = "123".to_string(); - let value = "Record Value".to_string(); - let tags = r#"{"tagName1":"tag1","tagName2":"tag2"}"#.to_string(); - - wallet_add_wallet_record(&xtype, &id, &value, Some(&tags)) - .await - .unwrap(); - close_main_wallet().await.unwrap(); - } - - #[tokio::test] - async fn test_wallet_record_add_with_no_tag() { - _create_and_open_wallet().await.unwrap(); - - let xtype = RecordCategory::default().to_string(); - let id = "123".to_string(); - let value = "Record Value".to_string(); - - wallet_add_wallet_record(&xtype, &id, &value, None) - .await - .unwrap(); - close_main_wallet().await.unwrap(); - } - - #[tokio::test] - async fn test_wallet_record_add_fails_with_duplication_error() { - _create_and_open_wallet().await.unwrap(); - - let xtype = RecordCategory::default().to_string(); - let id = "123".to_string(); - let value = "Record Value".to_string(); - - wallet_add_wallet_record(&xtype, &id, &value, None) - .await - .unwrap(); - let err = wallet_add_wallet_record(&xtype, &id, &value, None) - .await - .unwrap_err(); - assert_eq!(err.kind(), LibvcxErrorKind::DuplicationWalletRecord); - close_main_wallet().await.unwrap(); - } - - #[tokio::test] - async fn test_wallet_record_get_fails_if_record_does_not_exist() { - _create_and_open_wallet().await.unwrap(); - - let xtype = RecordCategory::default().to_string(); - let id = "123".to_string(); - let options = json!({ - "retrieveType": true, - "retrieveValue": true, - "retrieveTags": false - }) - .to_string(); - let _err = wallet_get_wallet_record(&xtype, &id, &options) - .await - .unwrap_err(); - // copilot demo: example - close_main_wallet().await.unwrap(); - } - - async fn _add_and_get_wallet_record() -> LibvcxResult<()> { - let xtype = RecordCategory::default().to_string(); - let id = "123".to_string(); - let value = "Record Value".to_string(); - let tags = r#"{"tagName1":"tag1","tagName2":"tag2"}"#.to_string(); - - wallet_add_wallet_record(&xtype, &id, &value, Some(&tags)).await?; - - let options = json!({ - "retrieveType": true, - "retrieveValue": true, - "retrieveTags": true - }) - .to_string(); - - let record = wallet_get_wallet_record(&xtype, &id, &options).await?; - let record: IndyWalletRecord = serde_json::from_str(&record)?; - assert_eq!(record.value.unwrap(), value); - Ok(()) - } - - #[tokio::test] - async fn test_wallet_record_delete() { - _create_and_open_wallet().await.unwrap(); - - let xtype = RecordCategory::default().to_string(); - let id = "123".to_string(); - let value = "Record Value".to_string(); - - wallet_add_wallet_record(&xtype, &id, &value, None) - .await - .unwrap(); - wallet_delete_wallet_record(&xtype, &id).await.unwrap(); - let err = wallet_delete_wallet_record(&xtype, &id).await.unwrap_err(); - assert_eq!(err.kind(), LibvcxErrorKind::WalletRecordNotFound); - let err = wallet_get_wallet_record(&xtype, &id, "{}") - .await - .unwrap_err(); - assert_eq!(err.kind(), LibvcxErrorKind::WalletRecordNotFound); - } - - #[tokio::test] - async fn test_wallet_export_import() { - let _setup = SetupMocks::init(); - let wallet_name = uuid::Uuid::new_v4().to_string(); - let export_file = TempFile::prepare_path(&wallet_name); - let wallet_config = WalletConfig { - wallet_name, - wallet_key: DEFAULT_WALLET_KEY.into(), - wallet_key_derivation: WALLET_KDF_RAW.into(), - wallet_type: None, - storage_config: None, - storage_credentials: None, - rekey: None, - rekey_derivation_method: None, - }; - create_and_open_as_main_wallet(&wallet_config) - .await - .unwrap(); - let backup_key = DEFAULT_WALLET_BACKUP_KEY; - export_main_wallet(&export_file.path.to_string(), backup_key) - .await - .unwrap(); - close_main_wallet().await.unwrap(); - delete_wallet(&wallet_config).await.unwrap(); - let import_config: RestoreWalletConfigs = serde_json::from_value(json!({ - "wallet_name": wallet_config.wallet_name.clone(), - "wallet_key": wallet_config.wallet_key.clone(), - "exported_wallet_path": export_file.path, - "backup_key": backup_key, - "wallet_key_derivation": WALLET_KDF_RAW - })) - .unwrap(); - wallet_import(&import_config).await.unwrap(); - delete_wallet(&wallet_config).await.unwrap(); - } - - #[tokio::test] - async fn test_wallet_open_with_incorrect_key_fails() { - let _setup = SetupMocks::init(); - let wallet_name = uuid::Uuid::new_v4().to_string(); - let _export_file = TempFile::prepare_path(&wallet_name); - let mut wallet_config = WalletConfig { - wallet_name, - wallet_key: DEFAULT_WALLET_KEY.into(), - wallet_key_derivation: WALLET_KDF_RAW.into(), - wallet_type: None, - storage_config: None, - storage_credentials: None, - rekey: None, - rekey_derivation_method: None, - }; - create_and_open_as_main_wallet(&wallet_config) - .await - .unwrap(); - close_main_wallet().await.unwrap(); - wallet_config.wallet_key = "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFA2cAA".to_string(); - let err = open_as_main_wallet(&wallet_config).await.unwrap_err(); - assert_eq!(err.kind(), LibvcxErrorKind::WalletAccessFailed); - } - - #[tokio::test] - async fn test_wallet_open_with_wrong_name_fails() { - let _setup = SetupMocks::init(); - - let wallet_config: WalletConfig = serde_json::from_value(json!({ - "wallet_name": "different_wallet_name", - "wallet_key": DEFAULT_WALLET_KEY, - "wallet_key_derivation": WALLET_KDF_RAW, - })) - .unwrap(); - - assert_eq!( - open_as_main_wallet(&wallet_config) - .await - .unwrap_err() - .kind(), - LibvcxErrorKind::WalletNotFound - ) - } - - #[tokio::test] - async fn test_wallet_open_of_imported_wallet_succeeds() { - let _setup = SetupMocks::init(); - - let (export_wallet_path, wallet_name, wallet_config) = - _create_main_wallet_and_its_backup().await; - - delete_wallet(&wallet_config).await.unwrap(); - - let import_config = RestoreWalletConfigs { - wallet_name: wallet_name.clone(), - wallet_key: DEFAULT_WALLET_KEY.into(), - exported_wallet_path: export_wallet_path.path.clone(), - backup_key: DEFAULT_WALLET_BACKUP_KEY.to_string(), - wallet_key_derivation: Some(WALLET_KDF_RAW.into()), - }; - wallet_import(&import_config).await.unwrap(); - - let wallet_config: WalletConfig = serde_json::from_value(json!({ - "wallet_name": &wallet_name, - "wallet_key": DEFAULT_WALLET_KEY, - "wallet_key_derivation": WALLET_KDF_RAW, - })) - .unwrap(); - - open_as_main_wallet(&wallet_config).await.unwrap(); - } - - #[tokio::test] - async fn test_wallet_import_of_opened_wallet_fails() { - let _setup = SetupMocks::init(); - - let (export_wallet_path, wallet_name, wallet_config) = - _create_main_wallet_and_its_backup().await; - - open_as_main_wallet(&wallet_config).await.unwrap(); - - let import_config = RestoreWalletConfigs { - wallet_name, - wallet_key: DEFAULT_WALLET_KEY.into(), - exported_wallet_path: export_wallet_path.path.clone(), - backup_key: DEFAULT_WALLET_BACKUP_KEY.to_string(), - wallet_key_derivation: None, - }; - assert_eq!( - wallet_import(&import_config).await.unwrap_err().kind(), - LibvcxErrorKind::DuplicationWallet - ) - } - - #[tokio::test] - async fn test_wallet_record_update() { - _create_and_open_wallet().await.unwrap(); - - let xtype = RecordCategory::default().to_string(); - let id = "123".to_string(); - let value = "Record Value".to_string(); - let new_value = "New Record Value".to_string(); - - let err = wallet_update_wallet_record_value(&xtype, &id, &new_value) - .await - .unwrap_err(); - assert_eq!(err.kind(), LibvcxErrorKind::WalletRecordNotFound); - wallet_add_wallet_record(&xtype, &id, &value, None) - .await - .unwrap(); - wallet_update_wallet_record_value(&xtype, &id, &new_value) - .await - .unwrap(); - let record = wallet_get_wallet_record(&xtype, &id, "{}").await.unwrap(); - let record: IndyWalletRecord = serde_json::from_str(&record).unwrap(); - assert_eq!(record.value.unwrap(), new_value); - } -} diff --git a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet/askar.rs b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet/askar.rs new file mode 100644 index 0000000000..84ecd59e15 --- /dev/null +++ b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet/askar.rs @@ -0,0 +1,205 @@ +use std::sync::{Arc, RwLock}; + +use aries_vcx_core::{ + anoncreds::base_anoncreds::BaseAnonCreds, + global::settings::DEFAULT_LINK_SECRET_ALIAS, + wallet::{ + askar::{ + askar_import_config::AskarImportConfig, askar_wallet_config::AskarWalletConfig, + AskarWallet, + }, + base_wallet::ManageWallet, + }, +}; + +use crate::{ + api_vcx::api_global::{ + profile::{get_main_anoncreds, try_get_main_wallet}, + wallet::{get_main_wallet, setup_global_anoncreds, BaseWallet}, + }, + errors::{ + error::{LibvcxError, LibvcxErrorKind, LibvcxResult}, + mapping_from_ariesvcxcore::map_ariesvcx_core_result, + }, +}; + +pub static GLOBAL_ASKAR_WALLET: RwLock>> = RwLock::new(None); + +fn setup_global_wallet(wallet: Arc) -> LibvcxResult<()> { + let mut b_wallet = GLOBAL_ASKAR_WALLET.write()?; + *b_wallet = Some(wallet); + + setup_global_anoncreds() +} + +pub async fn open_as_main_wallet( + wallet_config: &AskarWalletConfig, +) -> LibvcxResult> { + let wallet = Arc::new(wallet_config.open_wallet().await?); + setup_global_wallet(wallet.clone())?; + Ok(wallet) +} + +pub async fn create_and_open_as_main_wallet( + wallet_config: &AskarWalletConfig, +) -> LibvcxResult> { + let wallet = Arc::new(wallet_config.create_wallet().await?); + + setup_global_wallet(wallet.clone())?; + Ok(wallet) +} + +pub async fn close_main_wallet() -> LibvcxResult<()> { + let wallet = try_get_main_wallet()?; + match wallet { + None => { + warn!("Skipping wallet close, no global wallet component available.") + } + Some(wallet) => { + wallet.close_wallet().await?; + let mut b_wallet = GLOBAL_ASKAR_WALLET.write()?; + *b_wallet = None; + } + } + Ok(()) +} + +pub async fn create_main_wallet(config: &AskarWalletConfig) -> LibvcxResult<()> { + create_and_open_as_main_wallet(config).await?; + let wallet = get_main_wallet()?; + + // If MS is already in wallet then just continue + get_main_anoncreds()? + .prover_create_link_secret(wallet.as_ref(), &DEFAULT_LINK_SECRET_ALIAS.to_string()) + .await + .ok(); + + // TODO: enable when closing askar wallet is implemented + // close_main_wallet().await?; + Ok(()) +} + +pub async fn wallet_import(config: &AskarImportConfig) -> LibvcxResult<()> { + map_ariesvcx_core_result(config.import_wallet().await) +} + +pub async fn wallet_migrate(wallet_config: &impl ManageWallet) -> LibvcxResult<()> { + let src_wallet = get_main_wallet()?; + info!("Opening target wallet."); + let dest_wallet = wallet_config.create_wallet().await?; + + let migration_res = wallet_migrator::migrate_wallet( + src_wallet.as_ref(), + &dest_wallet, + wallet_migrator::vdrtools2credx::migrate_any_record, + ) + .await; + + migration_res.map_err(|e| LibvcxError::from_msg(LibvcxErrorKind::WalletMigrationFailed, e)) +} + +#[cfg(test)] +pub mod test_utils { + use aries_vcx_core::wallet::askar::{ + askar_wallet_config::AskarWalletConfig, key_method::KeyMethod, + }; + use test_utils::devsetup::TempFile; + use uuid::Uuid; + + // use crate::api_vcx::api_global::wallet::askar::open_main_wallet; + use crate::api_vcx::api_global::wallet::askar::open_as_main_wallet; + use crate::{ + api_vcx::api_global::wallet::{ + askar::{create_and_open_as_main_wallet, create_main_wallet}, + test_utils::setup_wallet_backup, + }, + errors::error::LibvcxResult, + }; + + pub async fn _create_main_wallet_and_its_backup() -> (TempFile, String, AskarWalletConfig) { + let wallet_config = AskarWalletConfig::new( + "sqlite://:memory:", + KeyMethod::Unprotected, + "", + &Uuid::new_v4().to_string(), + ); + + let wallet_name = &format!("export_test_wallet_{}", uuid::Uuid::new_v4()); + + let export_file = TempFile::prepare_path(wallet_name); + + let wallet = create_and_open_as_main_wallet(&wallet_config) + .await + .unwrap(); + + setup_wallet_backup(wallet.as_ref(), &export_file).await; + + (export_file, wallet_name.to_string(), wallet_config) + } + + pub async fn _create_and_open_wallet() -> LibvcxResult { + let config_wallet: AskarWalletConfig = AskarWalletConfig::new( + "sqlite://:memory:", + KeyMethod::Unprotected, + "", + &Uuid::new_v4().to_string(), + ); + create_main_wallet(&config_wallet).await?; + open_as_main_wallet(&config_wallet).await?; + Ok(config_wallet) + } +} + +#[cfg(test)] +pub mod tests { + use test_utils::devsetup::SetupMocks; + + use crate::api_vcx::api_global::wallet::askar::create_main_wallet; + + #[tokio::test] + async fn test_wallet_migrate() { + use aries_vcx_core::wallet::askar::{ + askar_wallet_config::AskarWalletConfig, key_method::KeyMethod, + }; + use uuid::Uuid; + + use crate::api_vcx::api_global::wallet::askar::create_and_open_as_main_wallet; + + let config = AskarWalletConfig::new( + "sqlite://:memory:", + KeyMethod::Unprotected, + "", + &Uuid::new_v4().to_string(), + ); + + create_and_open_as_main_wallet(&config).await.unwrap(); + + let new_config = AskarWalletConfig::new( + "sqlite://:memory:", + KeyMethod::Unprotected, + "", + &Uuid::new_v4().to_string(), + ); + + super::wallet_migrate(&new_config).await.unwrap(); + } + + #[tokio::test] + async fn test_wallet_create() { + use aries_vcx_core::wallet::askar::{ + askar_wallet_config::AskarWalletConfig, key_method::KeyMethod, + }; + use uuid::Uuid; + + let _setup = SetupMocks::init(); + + let config = AskarWalletConfig::new( + "sqlite://:memory:", + KeyMethod::Unprotected, + "", + &Uuid::new_v4().to_string(), + ); + + create_main_wallet(&config).await.unwrap(); + } +} diff --git a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet/indy.rs b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet/indy.rs new file mode 100644 index 0000000000..aa14510573 --- /dev/null +++ b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet/indy.rs @@ -0,0 +1,341 @@ +use std::sync::{Arc, RwLock}; + +use aries_vcx_core::{ + anoncreds::base_anoncreds::BaseAnonCreds, + global::settings::DEFAULT_LINK_SECRET_ALIAS, + wallet::{ + base_wallet::{BaseWallet, ImportWallet, ManageWallet}, + indy::{ + indy_import_config::IndyImportConfig, indy_wallet_config::IndyWalletConfig, + IndySdkWallet, + }, + }, +}; + +use crate::{ + api_vcx::api_global::{ + profile::{get_main_anoncreds, try_get_main_wallet}, + wallet::{get_main_wallet, setup_global_anoncreds}, + }, + errors::{ + error::{LibvcxError, LibvcxErrorKind, LibvcxResult}, + mapping_from_ariesvcxcore::map_ariesvcx_core_result, + }, +}; + +pub static GLOBAL_INDY_WALLET: RwLock>> = RwLock::new(None); + +fn setup_global_wallet(wallet: Arc) -> LibvcxResult<()> { + let mut b_wallet = GLOBAL_INDY_WALLET.write()?; + *b_wallet = Some(wallet); + + setup_global_anoncreds() +} + +pub async fn open_as_main_wallet( + wallet_config: &IndyWalletConfig, +) -> LibvcxResult> { + let wallet = Arc::new(wallet_config.open_wallet().await?); + setup_global_wallet(wallet.clone())?; + Ok(wallet) +} + +pub async fn create_and_open_as_main_wallet( + wallet_config: &IndyWalletConfig, +) -> LibvcxResult> { + let wallet = Arc::new(wallet_config.create_wallet().await?); + + setup_global_wallet(wallet.clone())?; + Ok(wallet) +} + +pub async fn close_main_wallet() -> LibvcxResult<()> { + let wallet = try_get_main_wallet()?; + match wallet { + None => { + warn!("Skipping wallet close, no global wallet component available.") + } + Some(wallet) => { + wallet.close_wallet().await?; + let mut b_wallet = GLOBAL_INDY_WALLET.write()?; + *b_wallet = None; + } + } + Ok(()) +} + +pub async fn create_main_wallet(config: &IndyWalletConfig) -> LibvcxResult<()> { + let wallet = create_and_open_as_main_wallet(config).await?; + trace!("Created wallet {:?}", wallet); + let wallet = get_main_wallet()?; + + // If MS is already in wallet then just continue + get_main_anoncreds()? + .prover_create_link_secret(wallet.as_ref(), &DEFAULT_LINK_SECRET_ALIAS.to_string()) + .await + .ok(); + + close_main_wallet().await?; + Ok(()) +} + +pub async fn wallet_import(config: &IndyImportConfig) -> LibvcxResult<()> { + map_ariesvcx_core_result(config.import_wallet().await) +} + +pub async fn wallet_migrate(wallet_config: &IndyWalletConfig) -> LibvcxResult<()> { + let src_wallet = get_main_wallet()?; + info!("Opening target wallet."); + let dest_wallet = wallet_config.create_wallet().await?; + + let migration_res = wallet_migrator::migrate_wallet( + src_wallet.as_ref(), + &dest_wallet, + wallet_migrator::vdrtools2credx::migrate_any_record, + ) + .await; + + migration_res.map_err(|e| LibvcxError::from_msg(LibvcxErrorKind::WalletMigrationFailed, e)) +} + +#[cfg(test)] +pub mod test_utils { + use aries_vcx_core::global::settings::{DEFAULT_WALLET_KEY, WALLET_KDF_RAW}; + use test_utils::devsetup::TempFile; + + use crate::{ + api_vcx::api_global::wallet::{ + indy::{ + create_and_open_as_main_wallet, create_main_wallet, open_as_main_wallet, + IndyWalletConfig, + }, + test_utils::setup_wallet_backup, + }, + errors::error::LibvcxResult, + }; + + pub async fn _create_and_open_wallet() -> LibvcxResult { + let wallet_name = format!("test_create_wallet_{}", uuid::Uuid::new_v4()); + let config_wallet: IndyWalletConfig = serde_json::from_value(json!({ + "wallet_name": wallet_name, + "wallet_key": DEFAULT_WALLET_KEY, + "wallet_key_derivation": WALLET_KDF_RAW + }))?; + create_main_wallet(&config_wallet).await?; + open_as_main_wallet(&config_wallet).await?; + Ok(config_wallet) + } + + pub async fn _create_main_wallet_and_its_backup() -> (TempFile, String, IndyWalletConfig) { + let wallet_name = format!("test_create_wallet_{}", uuid::Uuid::new_v4()); + + let wallet_config = IndyWalletConfig { + wallet_name: wallet_name.clone(), + wallet_key: DEFAULT_WALLET_KEY.into(), + wallet_key_derivation: WALLET_KDF_RAW.into(), + wallet_type: None, + storage_config: None, + storage_credentials: None, + rekey: None, + rekey_derivation_method: None, + }; + let export_file = TempFile::prepare_path(&wallet_name); + + let wallet = create_and_open_as_main_wallet(&wallet_config) + .await + .unwrap(); + + setup_wallet_backup(wallet.as_ref(), &export_file).await; + + (export_file, wallet_name.to_string(), wallet_config) + } +} + +#[cfg(test)] +pub mod tests { + use aries_vcx_core::{ + global::settings::{DEFAULT_WALLET_BACKUP_KEY, DEFAULT_WALLET_KEY, WALLET_KDF_RAW}, + wallet::base_wallet::ManageWallet, + }; + use test_utils::devsetup::{SetupMocks, TempFile}; + + use crate::{ + api_vcx::api_global::wallet::{ + export_main_wallet, + indy::{ + close_main_wallet, create_and_open_as_main_wallet, create_main_wallet, + open_as_main_wallet, test_utils::_create_main_wallet_and_its_backup, wallet_import, + IndyImportConfig, IndyWalletConfig, + }, + }, + errors::error::LibvcxErrorKind, + }; + + #[tokio::test] + async fn test_wallet_create() { + let _setup = SetupMocks::init(); + + let wallet_name = format!("test_create_wallet_{}", uuid::Uuid::new_v4()); + let config: IndyWalletConfig = serde_json::from_value(json!({ + "wallet_name": wallet_name, + "wallet_key": DEFAULT_WALLET_KEY, + "wallet_key_derivation": WALLET_KDF_RAW + })) + .unwrap(); + + create_main_wallet(&config).await.unwrap(); + } + + #[tokio::test] + async fn test_wallet_migrate() { + let wallet_name = format!("test_create_wallet_{}", uuid::Uuid::new_v4()); + let config: IndyWalletConfig = serde_json::from_value(json!({ + "wallet_name": wallet_name, + "wallet_key": DEFAULT_WALLET_KEY, + "wallet_key_derivation": WALLET_KDF_RAW + })) + .unwrap(); + + create_and_open_as_main_wallet(&config).await.unwrap(); + + let wallet_name = format!("test_migrate_wallet_{}", uuid::Uuid::new_v4()); + let new_config: IndyWalletConfig = serde_json::from_value(json!({ + "wallet_name": wallet_name, + "wallet_key": DEFAULT_WALLET_KEY, + "wallet_key_derivation": WALLET_KDF_RAW + })) + .unwrap(); + + super::wallet_migrate(&new_config).await.unwrap(); + } + + #[tokio::test] + async fn test_wallet_export_import() { + let _setup = SetupMocks::init(); + let wallet_name = uuid::Uuid::new_v4().to_string(); + let export_file = TempFile::prepare_path(&wallet_name); + let wallet_config = IndyWalletConfig { + wallet_name, + wallet_key: DEFAULT_WALLET_KEY.into(), + wallet_key_derivation: WALLET_KDF_RAW.into(), + wallet_type: None, + storage_config: None, + storage_credentials: None, + rekey: None, + rekey_derivation_method: None, + }; + create_and_open_as_main_wallet(&wallet_config) + .await + .unwrap(); + let backup_key = DEFAULT_WALLET_BACKUP_KEY; + export_main_wallet(&export_file.path.to_string(), backup_key) + .await + .unwrap(); + close_main_wallet().await.unwrap(); + wallet_config.delete_wallet().await.unwrap(); + let import_config: IndyImportConfig = serde_json::from_value(json!({ + "wallet_name": wallet_config.wallet_name.clone(), + "wallet_key": wallet_config.wallet_key.clone(), + "exported_wallet_path": export_file.path, + "backup_key": backup_key, + "wallet_key_derivation": WALLET_KDF_RAW + })) + .unwrap(); + wallet_import(&import_config).await.unwrap(); + wallet_config.delete_wallet().await.unwrap(); + } + + #[tokio::test] + async fn test_wallet_open_with_incorrect_key_fails() { + let _setup = SetupMocks::init(); + let wallet_name = uuid::Uuid::new_v4().to_string(); + let _export_file = TempFile::prepare_path(&wallet_name); + let mut wallet_config = IndyWalletConfig { + wallet_name, + wallet_key: DEFAULT_WALLET_KEY.into(), + wallet_key_derivation: WALLET_KDF_RAW.into(), + wallet_type: None, + storage_config: None, + storage_credentials: None, + rekey: None, + rekey_derivation_method: None, + }; + create_and_open_as_main_wallet(&wallet_config) + .await + .unwrap(); + close_main_wallet().await.unwrap(); + wallet_config.wallet_key = "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFA2cAA".to_string(); + let err = open_as_main_wallet(&wallet_config).await.unwrap_err(); + assert_eq!(err.kind(), LibvcxErrorKind::WalletAccessFailed); + } + + #[tokio::test] + async fn test_wallet_open_with_wrong_name_fails() { + let _setup = SetupMocks::init(); + + let wallet_config: IndyWalletConfig = serde_json::from_value(json!({ + "wallet_name": "different_wallet_name", + "wallet_key": DEFAULT_WALLET_KEY, + "wallet_key_derivation": WALLET_KDF_RAW, + })) + .unwrap(); + + assert_eq!( + open_as_main_wallet(&wallet_config) + .await + .unwrap_err() + .kind(), + LibvcxErrorKind::WalletNotFound + ) + } + + #[tokio::test] + async fn test_wallet_open_of_imported_wallet_succeeds() { + let _setup = SetupMocks::init(); + + let (export_wallet_path, wallet_name, wallet_config) = + _create_main_wallet_and_its_backup().await; + + wallet_config.delete_wallet().await.unwrap(); + + let import_config = IndyImportConfig { + wallet_name: wallet_name.clone(), + wallet_key: DEFAULT_WALLET_KEY.into(), + exported_wallet_path: export_wallet_path.path.clone(), + backup_key: DEFAULT_WALLET_BACKUP_KEY.to_string(), + wallet_key_derivation: Some(WALLET_KDF_RAW.into()), + }; + wallet_import(&import_config).await.unwrap(); + + let wallet_config: IndyWalletConfig = serde_json::from_value(json!({ + "wallet_name": &wallet_name, + "wallet_key": DEFAULT_WALLET_KEY, + "wallet_key_derivation": WALLET_KDF_RAW, + })) + .unwrap(); + + open_as_main_wallet(&wallet_config).await.unwrap(); + } + + #[tokio::test] + async fn test_wallet_import_of_opened_wallet_fails() { + let _setup = SetupMocks::init(); + + let (export_wallet_path, wallet_name, wallet_config) = + _create_main_wallet_and_its_backup().await; + + open_as_main_wallet(&wallet_config).await.unwrap(); + + let import_config = IndyImportConfig { + wallet_name, + wallet_key: DEFAULT_WALLET_KEY.into(), + exported_wallet_path: export_wallet_path.path.clone(), + backup_key: DEFAULT_WALLET_BACKUP_KEY.to_string(), + wallet_key_derivation: None, + }; + assert_eq!( + wallet_import(&import_config).await.unwrap_err().kind(), + LibvcxErrorKind::DuplicationWallet + ) + } +} diff --git a/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet/mod.rs b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet/mod.rs new file mode 100644 index 0000000000..fdb32fc8d4 --- /dev/null +++ b/aries/misc/legacy/libvcx_core/src/api_vcx/api_global/wallet/mod.rs @@ -0,0 +1,447 @@ +#[cfg(feature = "askar_wallet")] +pub mod askar; +#[cfg(feature = "askar_wallet")] +pub use askar as wallet; + +#[cfg(feature = "vdrtools_wallet")] +pub mod indy; +#[cfg(feature = "vdrtools_wallet")] +pub use indy as wallet; + +pub static GLOBAL_BASE_ANONCREDS: RwLock>> = RwLock::new(None); + +pub fn setup_global_anoncreds() -> LibvcxResult<()> { + let base_anoncreds_impl = Arc::new(IndyCredxAnonCreds); + let mut b_anoncreds = GLOBAL_BASE_ANONCREDS.write()?; + *b_anoncreds = Some(base_anoncreds_impl); + Ok(()) +} + +pub async fn export_main_wallet(path: &str, backup_key: &str) -> LibvcxResult<()> { + let main_wallet = get_main_wallet()?; + map_ariesvcx_core_result(main_wallet.as_ref().export_wallet(path, backup_key).await) +} + +use std::{ + str::FromStr, + sync::{Arc, RwLock}, +}; + +use aries_vcx::{ + aries_vcx_core::{ + anoncreds::credx_anoncreds::IndyCredxAnonCreds, wallet::structs_io::UnpackMessageOutput, + }, + protocols::mediated_connection::pairwise_info::PairwiseInfo, +}; +use aries_vcx_core::{ + errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind}, + wallet::{ + base_wallet::{ + did_wallet::DidWallet, issuer_config::IssuerConfig, record::Record, + record_category::RecordCategory, record_wallet::RecordWallet, + search_filter::SearchFilter, BaseWallet, + }, + indy::indy_wallet_record::IndyWalletRecord, + record_tags::RecordTags, + }, +}; +use public_key::{Key, KeyType}; + +use crate::{ + api_vcx::api_global::profile::{get_main_ledger_write, get_main_wallet}, + errors::{ + error::LibvcxResult, mapping_from_ariesvcx::map_ariesvcx_result, + mapping_from_ariesvcxcore::map_ariesvcx_core_result, + }, +}; + +#[cfg(all(feature = "vdrtools_wallet", feature = "askar_wallet"))] +compile_error!("features `vdrtools_wallet` and `askar_wallet` are mutually exclusive"); + +pub async fn key_for_local_did(did: &str) -> LibvcxResult { + let wallet = get_main_wallet()?; + + map_ariesvcx_core_result(wallet.key_for_did(did).await.map(|key| key.base58())) +} + +pub async fn wallet_sign(vk: &str, data_raw: &[u8]) -> LibvcxResult> { + let wallet = get_main_wallet()?; + + let verkey = Key::from_base58(vk, KeyType::Ed25519)?; + map_ariesvcx_core_result(wallet.sign(&verkey, data_raw).await) +} + +pub async fn wallet_verify(vk: &str, msg: &[u8], signature: &[u8]) -> LibvcxResult { + let wallet = get_main_wallet()?; + + let verkey = Key::from_base58(vk, KeyType::Ed25519)?; + map_ariesvcx_core_result(wallet.verify(&verkey, msg, signature).await) +} + +pub async fn replace_did_keys_start(did: &str) -> LibvcxResult { + let wallet = get_main_wallet()?; + + map_ariesvcx_core_result( + wallet + .replace_did_key_start(did, None) + .await + .map(|key| key.base58()), + ) +} + +pub async fn rotate_verkey_apply(did: &str, temp_vk: &str) -> LibvcxResult<()> { + let wallet = get_main_wallet()?; + map_ariesvcx_result( + aries_vcx::common::keys::rotate_verkey_apply( + wallet.as_ref(), + get_main_ledger_write()?.as_ref(), + &did.parse()?, + temp_vk, + ) + .await, + ) +} + +pub async fn wallet_unpack_message(payload: &[u8]) -> LibvcxResult { + let wallet = get_main_wallet()?; + map_ariesvcx_core_result(wallet.unpack_message(payload).await) +} + +pub async fn wallet_create_and_store_did(seed: Option<&str>) -> LibvcxResult { + let wallet = get_main_wallet()?; + let did_data = wallet.create_and_store_my_did(seed, None).await?; + Ok(PairwiseInfo { + pw_did: did_data.did().into(), + pw_vk: did_data.verkey().base58(), + }) +} + +pub async fn wallet_configure_issuer(enterprise_seed: &str) -> LibvcxResult { + let wallet = get_main_wallet()?; + map_ariesvcx_core_result(wallet.configure_issuer(enterprise_seed).await) +} + +pub async fn wallet_add_wallet_record( + type_: &str, + id: &str, + value: &str, + option: Option<&str>, +) -> LibvcxResult<()> { + let wallet = get_main_wallet()?; + let tags: Option = option.map(serde_json::from_str).transpose()?; + + let record = if let Some(record_tags) = tags { + Record::builder() + .name(id.into()) + .category(RecordCategory::from_str(type_)?) + .value(value.into()) + .tags(record_tags) + .build() + } else { + Record::builder() + .name(id.into()) + .category(RecordCategory::from_str(type_)?) + .value(value.into()) + .build() + }; + + map_ariesvcx_core_result(wallet.add_record(record).await) +} + +pub async fn wallet_update_wallet_record_value( + xtype: &str, + id: &str, + value: &str, +) -> LibvcxResult<()> { + let wallet = get_main_wallet()?; + map_ariesvcx_core_result( + wallet + .update_record_value(RecordCategory::from_str(xtype)?, id, value) + .await, + ) +} + +pub async fn wallet_update_wallet_record_tags( + xtype: &str, + id: &str, + tags_json: &str, +) -> LibvcxResult<()> { + let wallet = get_main_wallet()?; + let tags: RecordTags = serde_json::from_str(tags_json)?; + map_ariesvcx_core_result( + wallet + .update_record_tags(RecordCategory::from_str(xtype)?, id, tags) + .await, + ) +} + +pub async fn wallet_add_wallet_record_tags( + xtype: &str, + id: &str, + tags_json: &str, +) -> LibvcxResult<()> { + let wallet = get_main_wallet()?; + let record = wallet + .get_record(RecordCategory::from_str(xtype)?, id) + .await?; + + let tags = { + let mut tags: RecordTags = serde_json::from_str(tags_json)?; + tags.merge(record.tags().clone()); + tags + }; + + map_ariesvcx_core_result( + wallet + .update_record_tags(RecordCategory::from_str(xtype)?, id, tags) + .await, + ) +} + +pub async fn wallet_delete_wallet_record_tags( + xtype: &str, + id: &str, + tags_json: &str, +) -> LibvcxResult<()> { + let wallet = get_main_wallet()?; + let tags: RecordTags = serde_json::from_str(tags_json)?; + + let record = wallet + .get_record(RecordCategory::from_str(xtype)?, id) + .await?; + + let mut found_tags = record.tags().clone(); + for key in tags { + found_tags.remove(key); + } + + map_ariesvcx_core_result( + wallet + .update_record_tags(RecordCategory::from_str(xtype)?, id, found_tags) + .await, + ) +} + +pub async fn wallet_get_wallet_record( + xtype: &str, + id: &str, + _options: &str, +) -> LibvcxResult { + let wallet = get_main_wallet()?; + + map_ariesvcx_result( + wallet + .get_record(RecordCategory::from_str(xtype)?, id) + .await + .map(|res| { + let wallet_record = IndyWalletRecord::from_record(res)?; + + Ok(serde_json::to_string(&wallet_record)?) + })?, + ) +} + +pub async fn wallet_delete_wallet_record(xtype: &str, id: &str) -> LibvcxResult<()> { + let wallet = get_main_wallet()?; + map_ariesvcx_core_result( + wallet + .delete_record(RecordCategory::from_str(xtype)?, id) + .await, + ) +} + +pub async fn wallet_search_records(xtype: &str, query_json: &str) -> LibvcxResult { + let wallet = get_main_wallet()?; + let records = wallet + .search_record( + RecordCategory::from_str(xtype)?, + Some(SearchFilter::JsonFilter(query_json.into())), + ) + .await?; + + let indy_records = records + .into_iter() + .map(IndyWalletRecord::from_record) + .collect::, _>>()?; + + let res = serde_json::to_string(&indy_records) + .map_err(|err| AriesVcxCoreError::from_msg(AriesVcxCoreErrorKind::InvalidJson, err)); + + map_ariesvcx_core_result(res) +} + +#[cfg(test)] +pub mod test_utils { + use ::test_utils::devsetup::TempFile; + use aries_vcx::global::settings::DEFAULT_WALLET_BACKUP_KEY; + use aries_vcx_core::wallet::base_wallet::{ + record::Record, record_category::RecordCategory, BaseWallet, + }; + + use crate::api_vcx::api_global::wallet::{export_main_wallet, wallet::close_main_wallet}; + + pub async fn setup_wallet_backup(wallet: &impl BaseWallet, export_file: &TempFile) { + wallet.create_and_store_my_did(None, None).await.unwrap(); + + let new_record = Record::builder() + .name("id1".to_owned()) + .category(RecordCategory::default()) + .value("value1".to_owned()) + .build(); + + wallet.add_record(new_record).await.unwrap(); + export_main_wallet(&export_file.path, DEFAULT_WALLET_BACKUP_KEY) + .await + .unwrap(); + + close_main_wallet().await.unwrap(); + } +} + +// TODO: remove feature flag when closing wallet is implemented for askar +#[cfg(feature = "vdrtools_wallet")] +#[cfg(test)] +mod tests { + use aries_vcx_core::wallet::{ + base_wallet::record_category::RecordCategory, indy::indy_wallet_record::IndyWalletRecord, + }; + + use crate::{ + api_vcx::api_global::wallet::{ + wallet::{close_main_wallet, test_utils::_create_and_open_wallet}, + wallet_add_wallet_record, wallet_delete_wallet_record, wallet_get_wallet_record, + wallet_update_wallet_record_value, + }, + errors::error::{LibvcxErrorKind, LibvcxResult}, + }; + + #[tokio::test] + async fn test_wallet_record_add_with_tag() { + _create_and_open_wallet().await.unwrap(); + + let xtype = RecordCategory::default().to_string(); + let id = "123".to_string(); + let value = "Record Value".to_string(); + let tags = r#"{"tagName1":"tag1","tagName2":"tag2"}"#.to_string(); + wallet_add_wallet_record(&xtype, &id, &value, Some(&tags)) + .await + .unwrap(); + close_main_wallet().await.unwrap(); + } + + #[tokio::test] + async fn test_wallet_record_add_with_no_tag() { + _create_and_open_wallet().await.unwrap(); + + let xtype = RecordCategory::default().to_string(); + let id = "123".to_string(); + let value = "Record Value".to_string(); + + wallet_add_wallet_record(&xtype, &id, &value, None) + .await + .unwrap(); + close_main_wallet().await.unwrap(); + } + + #[tokio::test] + async fn test_wallet_record_add_fails_with_duplication_error() { + _create_and_open_wallet().await.unwrap(); + + let xtype = RecordCategory::default().to_string(); + let id = "123".to_string(); + let value = "Record Value".to_string(); + + wallet_add_wallet_record(&xtype, &id, &value, None) + .await + .unwrap(); + let err = wallet_add_wallet_record(&xtype, &id, &value, None) + .await + .unwrap_err(); + assert_eq!(err.kind(), LibvcxErrorKind::DuplicationWalletRecord); + close_main_wallet().await.unwrap(); + } + + #[tokio::test] + async fn test_wallet_record_get_fails_if_record_does_not_exist() { + _create_and_open_wallet().await.unwrap(); + + let xtype = RecordCategory::default().to_string(); + let id = "123".to_string(); + let options = json!({ + "retrieveType": true, + "retrieveValue": true, + "retrieveTags": false + }) + .to_string(); + let _err = wallet_get_wallet_record(&xtype, &id, &options) + .await + .unwrap_err(); + // copilot demo: example + close_main_wallet().await.unwrap(); + } + + async fn _add_and_get_wallet_record() -> LibvcxResult<()> { + let xtype = RecordCategory::default().to_string(); + let id = "123".to_string(); + let value = "Record Value".to_string(); + let tags = r#"{"tagName1":"tag1","tagName2":"tag2"}"#.to_string(); + + wallet_add_wallet_record(&xtype, &id, &value, Some(&tags)).await?; + + let options = json!({ + "retrieveType": true, + "retrieveValue": true, + "retrieveTags": true + }) + .to_string(); + + let record = wallet_get_wallet_record(&xtype, &id, &options).await?; + let record: IndyWalletRecord = serde_json::from_str(&record)?; + assert_eq!(record.value.unwrap(), value); + Ok(()) + } + + #[tokio::test] + async fn test_wallet_record_delete() { + _create_and_open_wallet().await.unwrap(); + + let xtype = RecordCategory::default().to_string(); + let id = "123".to_string(); + let value = "Record Value".to_string(); + + wallet_add_wallet_record(&xtype, &id, &value, None) + .await + .unwrap(); + wallet_delete_wallet_record(&xtype, &id).await.unwrap(); + let err = wallet_delete_wallet_record(&xtype, &id).await.unwrap_err(); + assert_eq!(err.kind(), LibvcxErrorKind::WalletRecordNotFound); + let err = wallet_get_wallet_record(&xtype, &id, "{}") + .await + .unwrap_err(); + assert_eq!(err.kind(), LibvcxErrorKind::WalletRecordNotFound); + } + + #[tokio::test] + async fn test_wallet_record_update() { + _create_and_open_wallet().await.unwrap(); + + let xtype = RecordCategory::default().to_string(); + let id = "123".to_string(); + let value = "Record Value".to_string(); + let new_value = "New Record Value".to_string(); + + let err = wallet_update_wallet_record_value(&xtype, &id, &new_value) + .await + .unwrap_err(); + assert_eq!(err.kind(), LibvcxErrorKind::WalletRecordNotFound); + wallet_add_wallet_record(&xtype, &id, &value, None) + .await + .unwrap(); + wallet_update_wallet_record_value(&xtype, &id, &new_value) + .await + .unwrap(); + let record = wallet_get_wallet_record(&xtype, &id, "{}").await.unwrap(); + let record: IndyWalletRecord = serde_json::from_str(&record).unwrap(); + assert_eq!(record.value.unwrap(), new_value); + } +} diff --git a/aries/misc/legacy/libvdrtools/indy-wallet/src/iterator.rs b/aries/misc/legacy/libvdrtools/indy-wallet/src/iterator.rs index d72d733a09..81125d769d 100644 --- a/aries/misc/legacy/libvdrtools/indy-wallet/src/iterator.rs +++ b/aries/misc/legacy/libvdrtools/indy-wallet/src/iterator.rs @@ -6,7 +6,7 @@ use super::{ encryption::decrypt_storage_record, storage::StorageIterator, wallet::Keys, WalletRecord, }; -pub(super) struct WalletIterator { +pub struct WalletIterator { storage_iterator: Box, keys: Arc, } diff --git a/aries/misc/legacy/libvdrtools/indy-wallet/src/lib.rs b/aries/misc/legacy/libvdrtools/indy-wallet/src/lib.rs index 84bac326bb..7004da52d3 100644 --- a/aries/misc/legacy/libvdrtools/indy-wallet/src/lib.rs +++ b/aries/misc/legacy/libvdrtools/indy-wallet/src/lib.rs @@ -8,7 +8,7 @@ use std::{ }; use indy_api_types::{ - domain::wallet::{CacheConfig, Config, Credentials, ExportConfig, IndyRecord, Tags}, + domain::wallet::{CacheConfig, Config, Credentials, ExportConfig, Tags}, errors::prelude::*, WalletHandle, }; @@ -16,7 +16,8 @@ use indy_utils::{ crypto::chacha20poly1305_ietf::{self, Key as MasterKey}, secret, }; -use log::{error, info, trace, warn}; +use iterator::WalletIterator; +use log::trace; use serde::{Deserialize, Serialize}; use serde_json::Value as SValue; @@ -31,7 +32,7 @@ use crate::{ }; mod encryption; -mod iterator; +pub mod iterator; mod query_encryption; mod storage; @@ -42,14 +43,6 @@ mod cache; mod export_import; mod wallet; -#[derive(Debug)] -pub struct MigrationResult { - migrated: u32, - skipped: u32, - duplicated: u32, - failed: u32, -} - #[allow(clippy::type_complexity)] pub struct WalletService { storage_types: Mutex>>, @@ -709,126 +702,9 @@ impl WalletService { Ok(()) } - pub async fn migrate_records( - &self, - old_wh: WalletHandle, - new_wh: WalletHandle, - mut migrate_fn: impl FnMut(IndyRecord) -> Result, E>, - ) -> IndyResult - where - E: std::fmt::Display, - { - let old_wallet = self.get_wallet(old_wh).await?; - let new_wallet = self.get_wallet(new_wh).await?; - - let mut records = old_wallet.get_all().await?; - let total = records.get_total_count()?; - info!("Migrating {total:?} records"); - let mut num_record = 0; - let mut migration_result = MigrationResult { - migrated: 0, - skipped: 0, - duplicated: 0, - failed: 0, - }; - - while let Some(source_record) = records.next().await? { - num_record += 1; - if num_record % 1000 == 1 { - warn!( - "Migrating wallet record number {num_record} / {total:?}, intermediary \ - migration result: ${migration_result:?}" - ); - } - trace!("Migrating record: {:?}", source_record); - let unwrapped_type_ = match &source_record.type_ { - None => { - warn!( - "Skipping item missing 'type' field, record ({num_record}): \ - {source_record:?}" - ); - migration_result.skipped += 1; - continue; - } - Some(type_) => type_.clone(), - }; - let unwrapped_value = match &source_record.value { - None => { - warn!( - "Skipping item missing 'value' field, record ({num_record}): \ - {source_record:?}" - ); - migration_result.skipped += 1; - continue; - } - Some(value) => value.clone(), - }; - let unwrapped_tags = match &source_record.tags { - None => HashMap::new(), - Some(tags) => tags.clone(), - }; - - let record = IndyRecord { - type_: unwrapped_type_, - id: source_record.id.clone(), - value: unwrapped_value, - tags: unwrapped_tags, - }; - - let migrated_record = match migrate_fn(record) { - Ok(record) => match record { - None => { - warn!("Skipping non-migratable record ({num_record}): {source_record:?}"); - migration_result.skipped += 1; - continue; - } - Some(record) => record, - }, - Err(err) => { - warn!( - "Skipping item due failed item migration, record ({num_record}): \ - {source_record:?}, err: {err}" - ); - migration_result.failed += 1; - continue; - } - }; - - match new_wallet - .add( - &migrated_record.type_, - &migrated_record.id, - &migrated_record.value, - &migrated_record.tags, - false, - ) - .await - { - Err(err) => match err.kind() { - IndyErrorKind::WalletItemAlreadyExists => { - trace!( - "Record type: {migrated_record:?} already exists in destination \ - wallet, skipping" - ); - migration_result.duplicated += 1; - continue; - } - _ => { - error!( - "Error adding record {migrated_record:?} to destination wallet: \ - {err:?}" - ); - migration_result.failed += 1; - return Err(err); - } - }, - Ok(()) => { - migration_result.migrated += 1; - } - } - } - warn!("Migration of total {total:?} records completed, result: ${migration_result:?}"); - Ok(migration_result) + pub async fn get_all(&self, handle: WalletHandle) -> IndyResult { + let wallet = self.get_wallet(handle).await?; + wallet.get_all().await } pub async fn export_wallet( diff --git a/aries/misc/legacy/libvdrtools/indy-wallet/src/wallet.rs b/aries/misc/legacy/libvdrtools/indy-wallet/src/wallet.rs index e21d29afff..3f11b26b8a 100644 --- a/aries/misc/legacy/libvdrtools/indy-wallet/src/wallet.rs +++ b/aries/misc/legacy/libvdrtools/indy-wallet/src/wallet.rs @@ -20,7 +20,7 @@ use crate::{ }; #[derive(Serialize, Deserialize)] -pub(super) struct Keys { +pub struct Keys { pub type_key: chacha20poly1305_ietf::Key, pub name_key: chacha20poly1305_ietf::Key, pub value_key: chacha20poly1305_ietf::Key, @@ -30,6 +30,7 @@ pub(super) struct Keys { pub tags_hmac_key: hmacsha256::Key, } +#[allow(clippy::new_without_default)] impl Keys { pub fn new() -> Keys { Keys { diff --git a/aries/misc/legacy/libvdrtools/src/controllers/wallet.rs b/aries/misc/legacy/libvdrtools/src/controllers/wallet.rs index 11eb3a8404..bc4eaf37ef 100644 --- a/aries/misc/legacy/libvdrtools/src/controllers/wallet.rs +++ b/aries/misc/legacy/libvdrtools/src/controllers/wallet.rs @@ -2,14 +2,14 @@ use std::sync::Arc; // use async_std::task::spawn_blocking; use indy_api_types::{ - domain::wallet::{Config, Credentials, ExportConfig, IndyRecord, KeyConfig}, + domain::wallet::{Config, Credentials, ExportConfig, KeyConfig}, errors::prelude::*, WalletHandle, }; use indy_utils::crypto::{ chacha20poly1305_ietf, chacha20poly1305_ietf::Key as MasterKey, randombytes, }; -use indy_wallet::{KeyDerivationData, MigrationResult, WalletService}; +use indy_wallet::{iterator::WalletIterator, KeyDerivationData, WalletService}; use crate::{services::CryptoService, utils::crypto::base58::ToBase58}; @@ -387,18 +387,8 @@ impl WalletController { res } - pub async fn migrate_records( - &self, - old_wh: WalletHandle, - new_wh: WalletHandle, - migrate_fn: impl FnMut(IndyRecord) -> Result, E>, - ) -> IndyResult - where - E: std::fmt::Display, - { - self.wallet_service - .migrate_records(old_wh, new_wh, migrate_fn) - .await + pub async fn get_all(&self, handle: WalletHandle) -> IndyResult { + self.wallet_service.get_all(handle).await } /// Generate wallet master key. diff --git a/aries/misc/legacy/libvdrtools/src/lib.rs b/aries/misc/legacy/libvdrtools/src/lib.rs index d8e22c6bb2..006e3b81f4 100644 --- a/aries/misc/legacy/libvdrtools/src/lib.rs +++ b/aries/misc/legacy/libvdrtools/src/lib.rs @@ -8,6 +8,7 @@ extern crate serde_derive; extern crate indy_utils; pub use indy_api_types as types; +pub use indy_wallet; #[macro_use] mod utils; diff --git a/aries/misc/test_utils/src/devsetup.rs b/aries/misc/test_utils/src/devsetup.rs index 88a044b470..2a03a0a305 100644 --- a/aries/misc/test_utils/src/devsetup.rs +++ b/aries/misc/test_utils/src/devsetup.rs @@ -36,8 +36,6 @@ use crate::devsetup::vdr_proxy_ledger::dev_build_profile_vdr_proxy_ledger; #[cfg(feature = "vdrtools_wallet")] pub mod vdrtools_wallet; -#[cfg(feature = "vdrtools_wallet")] -use crate::devsetup::vdrtools_wallet::dev_build_indy_wallet; const DEFAULT_AML_LABEL: &str = "eula"; @@ -212,7 +210,9 @@ pub async fn dev_build_featured_wallet(key_seed: &str) -> (String, impl BaseWall #[cfg(feature = "vdrtools_wallet")] return { info!("SetupProfile >> using indy wallet"); - dev_build_indy_wallet(key_seed).await + + use crate::devsetup::vdrtools_wallet::dev_setup_wallet_indy; + dev_setup_wallet_indy(key_seed).await }; #[cfg(not(feature = "vdrtools_wallet"))] diff --git a/aries/misc/test_utils/src/devsetup/vdrtools_wallet.rs b/aries/misc/test_utils/src/devsetup/vdrtools_wallet.rs index f7c13fc3e9..ca5d63ea1e 100644 --- a/aries/misc/test_utils/src/devsetup/vdrtools_wallet.rs +++ b/aries/misc/test_utils/src/devsetup/vdrtools_wallet.rs @@ -1,19 +1,15 @@ use aries_vcx_core::{ global::settings::{DEFAULT_WALLET_KEY, WALLET_KDF_RAW}, wallet::{ - base_wallet::BaseWallet, - indy::{ - wallet::{create_and_open_wallet, create_and_store_my_did}, - WalletConfig, - }, + base_wallet::{did_wallet::DidWallet, ManageWallet}, + indy::{indy_wallet_config::IndyWalletConfig, IndySdkWallet}, }, - WalletHandle, }; use log::info; -pub async fn dev_setup_wallet_indy(key_seed: &str) -> (String, WalletHandle) { +pub async fn dev_setup_wallet_indy(key_seed: &str) -> (String, IndySdkWallet) { info!("dev_setup_wallet_indy >>"); - let config_wallet = WalletConfig { + let config_wallet = IndyWalletConfig { wallet_name: format!("wallet_{}", uuid::Uuid::new_v4()), wallet_key: DEFAULT_WALLET_KEY.into(), wallet_key_derivation: WALLET_KDF_RAW.into(), @@ -23,18 +19,13 @@ pub async fn dev_setup_wallet_indy(key_seed: &str) -> (String, WalletHandle) { rekey: None, rekey_derivation_method: None, }; - let wallet_handle = create_and_open_wallet(&config_wallet).await.unwrap(); - // todo: can we just extract this away? not always we end up using it (alice test agent) - let (did, _vk) = create_and_store_my_did(wallet_handle, Some(key_seed), None) - .await - .unwrap(); - (did, wallet_handle) -} + let wallet = config_wallet.create_wallet().await.unwrap(); -pub async fn dev_build_indy_wallet(key_seed: &str) -> (String, impl BaseWallet) { - use aries_vcx_core::wallet::indy::IndySdkWallet; + let did_data = wallet + .create_and_store_my_did(Some(key_seed), None) + .await + .unwrap(); - let (public_did, wallet_handle) = dev_setup_wallet_indy(key_seed).await; - (public_did, IndySdkWallet::new(wallet_handle)) + (did_data.did().to_owned(), wallet) } diff --git a/aries/misc/test_utils/src/mock_wallet.rs b/aries/misc/test_utils/src/mock_wallet.rs index 7e3b58ce52..555ac7abc6 100644 --- a/aries/misc/test_utils/src/mock_wallet.rs +++ b/aries/misc/test_utils/src/mock_wallet.rs @@ -2,8 +2,14 @@ use aries_vcx_core::{ errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind, VcxCoreResult}, wallet::{ base_wallet::{ - did_data::DidData, record::Record, record_category::RecordCategory, - search_filter::SearchFilter, BaseWallet, DidWallet, RecordWallet, + did_data::DidData, + did_wallet::DidWallet, + issuer_config::IssuerConfig, + record::{AllRecords, PartialRecord, Record}, + record_category::RecordCategory, + record_wallet::RecordWallet, + search_filter::SearchFilter, + BaseWallet, }, record_tags::RecordTags, structs_io::UnpackMessageOutput, @@ -15,7 +21,34 @@ use public_key::{Key, KeyType}; #[derive(Debug)] pub struct MockWallet; -impl BaseWallet for MockWallet {} +pub struct MockAllRecords; + +#[async_trait] +impl AllRecords for MockAllRecords { + fn total_count(&self) -> VcxCoreResult> { + Ok(Some(0)) + } + + async fn next(&mut self) -> VcxCoreResult> { + Ok(None) + } +} + +#[async_trait] +#[allow(unused_variables)] +impl BaseWallet for MockWallet { + async fn export_wallet(&self, path: &str, backup_key: &str) -> VcxCoreResult<()> { + Ok(()) + } + + async fn close_wallet(&self) -> VcxCoreResult<()> { + Ok(()) + } + + async fn configure_issuer(&self, key_seed: &str) -> VcxCoreResult { + Ok(IssuerConfig::builder().build()) + } +} pub const DID: &str = "FhrSrYtQcw3p9xwf7NYemf"; pub const VERKEY: &str = "91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE"; @@ -23,6 +56,10 @@ pub const VERKEY: &str = "91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE"; #[async_trait] #[allow(unused_variables)] impl RecordWallet for MockWallet { + async fn all_records(&self) -> VcxCoreResult> { + Ok(Box::new(MockAllRecords {})) + } + async fn add_record(&self, record: Record) -> VcxCoreResult<()> { Ok(()) } diff --git a/aries/misc/wallet_migrator/src/error.rs b/aries/misc/wallet_migrator/src/error.rs index 5db1a8c183..b7cd400526 100644 --- a/aries/misc/wallet_migrator/src/error.rs +++ b/aries/misc/wallet_migrator/src/error.rs @@ -1,3 +1,4 @@ +use aries_vcx_core::errors::error::AriesVcxCoreError; use serde_json::Error as JsonError; use thiserror::Error as ThisError; use vdrtools::IndyError; @@ -10,6 +11,6 @@ pub enum MigrationError { Json(#[from] JsonError), #[error("Indy error: {0}")] Indy(#[from] IndyError), - #[error("Source and destination wallets must be different!")] - EqualWalletHandles, + #[error("VcxCore error: {0}")] + VcxCore(#[from] AriesVcxCoreError), } diff --git a/aries/misc/wallet_migrator/src/lib.rs b/aries/misc/wallet_migrator/src/lib.rs index d29b523efe..442ff675bf 100644 --- a/aries/misc/wallet_migrator/src/lib.rs +++ b/aries/misc/wallet_migrator/src/lib.rs @@ -4,93 +4,32 @@ pub mod vdrtools2credx; use std::fmt::Display; +use aries_vcx_core::wallet::base_wallet::{migrate::migrate_records, record::Record, BaseWallet}; use error::MigrationResult; -use log::{error, info}; +use log::info; pub use vdrtools::types::domain::wallet::IndyRecord; -use vdrtools::{Locator, WalletHandle}; - -use crate::error::MigrationError; /// Retrieves all records from the source wallet and migrates them /// by applying the `migrate_fn` argument. The records are then /// placed in the destination wallet. pub async fn migrate_wallet( - src_wallet_handle: WalletHandle, - dest_wallet_handle: WalletHandle, - migrate_fn: impl FnMut(IndyRecord) -> Result, E>, + src_wallet: &impl BaseWallet, + dest_wallet: &impl BaseWallet, + migrate_fn: impl FnMut(Record) -> Result, E>, ) -> MigrationResult<()> where E: Display, { info!("Starting wallet migration"); - if src_wallet_handle == dest_wallet_handle { - error!("Equal wallet handles: {src_wallet_handle:?} {dest_wallet_handle:?}"); - return Err(MigrationError::EqualWalletHandles); - } - info!( - "Migrating records from wallet with handle {src_wallet_handle:?} to wallet with handle \ - {dest_wallet_handle:?}" + "Migrating records from wallet with handle {src_wallet:?} to wallet with handle \ + {dest_wallet:?}" ); - Locator::instance() - .wallet_controller - .migrate_records(src_wallet_handle, dest_wallet_handle, migrate_fn) - .await?; + migrate_records(src_wallet, dest_wallet, migrate_fn).await?; - info!( - "Completed migration from wallet with handle {src_wallet_handle:?} to wallet with handle \ - {dest_wallet_handle:?}" - ); + info!("Migration completed"); Ok(()) } - -#[cfg(test)] -mod tests { - use vdrtools::{ - types::domain::wallet::{Config, Credentials, KeyDerivationMethod}, - Locator, - }; - - #[tokio::test] - #[should_panic] - async fn test_cant_open_wallet_twice() { - let wallet_key = "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY".to_owned(); - let wallet_name = "wallet_with_some_name".to_owned(); - - let credentials = Credentials { - key: wallet_key, - key_derivation_method: KeyDerivationMethod::RAW, - rekey: None, - rekey_derivation_method: KeyDerivationMethod::ARGON2I_MOD, - storage_credentials: None, - }; - - let config = Config { - id: wallet_name, - storage_type: None, - storage_config: None, - cache: None, - }; - - Locator::instance() - .wallet_controller - .create(config.clone(), credentials.clone()) - .await - .unwrap(); - - let _first_wh = Locator::instance() - .wallet_controller - .open(config.clone(), credentials.clone()) - .await - .unwrap(); - - let _second_wh = Locator::instance() - .wallet_controller - .open(config, credentials) - .await - .unwrap(); - } -} diff --git a/aries/misc/wallet_migrator/src/vdrtools2credx/mod.rs b/aries/misc/wallet_migrator/src/vdrtools2credx/mod.rs index 4cbbd1a405..b427ec507d 100644 --- a/aries/misc/wallet_migrator/src/vdrtools2credx/mod.rs +++ b/aries/misc/wallet_migrator/src/vdrtools2credx/mod.rs @@ -1,7 +1,7 @@ pub mod conv; +use aries_vcx_core::wallet::base_wallet::record::Record; use log::trace; -use vdrtools::types::domain::wallet::IndyRecord; use crate::error::MigrationResult; @@ -21,30 +21,52 @@ pub(crate) const INDY_REV_REG_DEF: &str = "Indy::RevocationRegistryDefinition"; pub(crate) const INDY_REV_REG_DEF_PRIV: &str = "Indy::RevocationRegistryDefinitionPrivate"; /// Contains the logic for record mapping and migration. -pub fn migrate_any_record(record: IndyRecord) -> MigrationResult> { +pub fn migrate_any_record(record: Record) -> MigrationResult> { trace!("Migrating wallet record {record:?}"); - let record = match record.type_.as_str() { + let record = match record.category().to_string().as_str() { // Indy wallet records - to be left alone! INDY_DID | INDY_KEY => Ok(Some(record)), // Master secret - INDY_MASTER_SECRET => Some(conv::convert_master_secret(record)).transpose(), + INDY_MASTER_SECRET => Ok(Some(Record::try_from_indy_record( + conv::convert_master_secret(record.into())?, + )?)), // Credential - INDY_CRED => Some(conv::convert_cred(record)).transpose(), - INDY_CRED_DEF => Some(conv::convert_cred_def(record)).transpose(), - INDY_CRED_DEF_PRIV => Some(conv::convert_cred_def_priv_key(record)).transpose(), - INDY_CRED_DEF_CR_PROOF => { - Some(conv::convert_cred_def_correctness_proof(record)).transpose() - } + INDY_CRED => Ok(Some(Record::try_from_indy_record(conv::convert_cred( + record.into(), + )?)?)), + INDY_CRED_DEF => Ok(Some(Record::try_from_indy_record(conv::convert_cred_def( + record.into(), + )?)?)), + INDY_CRED_DEF_PRIV => Ok(Some(Record::try_from_indy_record( + conv::convert_cred_def_priv_key(record.into())?, + )?)), + INDY_CRED_DEF_CR_PROOF => Ok(Some(Record::try_from_indy_record( + conv::convert_cred_def_correctness_proof(record.into())?, + )?)), // Schema - INDY_SCHEMA => Some(conv::convert_schema(record)).transpose(), - INDY_SCHEMA_ID => Some(conv::convert_schema_id(record)).transpose(), + INDY_SCHEMA => Ok(Some(Record::try_from_indy_record(conv::convert_schema( + record.into(), + )?)?)), + INDY_SCHEMA_ID => Ok(Some(Record::try_from_indy_record( + conv::convert_schema_id(record.into())?, + )?)), // Revocation registry - INDY_REV_REG => Some(conv::convert_rev_reg(record)).transpose(), - INDY_REV_REG_DELTA => Some(conv::convert_rev_reg_delta(record)).transpose(), - INDY_REV_REG_INFO => Some(conv::convert_rev_reg_info(record)).transpose(), - INDY_REV_REG_DEF => Some(conv::convert_rev_reg_def(record)).transpose(), - INDY_REV_REG_DEF_PRIV => Some(conv::convert_rev_reg_def_priv(record)).transpose(), + INDY_REV_REG => Ok(Some(Record::try_from_indy_record(conv::convert_rev_reg( + record.into(), + )?)?)), + INDY_REV_REG_DELTA => Ok(Some(Record::try_from_indy_record( + conv::convert_rev_reg_delta(record.into())?, + )?)), + INDY_REV_REG_INFO => Ok(Some(Record::try_from_indy_record( + conv::convert_rev_reg_info(record.into())?, + )?)), + INDY_REV_REG_DEF => Ok(Some(Record::try_from_indy_record( + conv::convert_rev_reg_def(record.into())?, + )?)), + INDY_REV_REG_DEF_PRIV => Ok(Some(Record::try_from_indy_record( + conv::convert_rev_reg_def_priv(record.into())?, + )?)), _ => Ok(None), // Ignore unknown/uninteresting records }; @@ -58,7 +80,7 @@ mod tests { use aries_vcx_core::{ anoncreds::credx_anoncreds::RevocationRegistryInfo, - wallet::base_wallet::record_category::RecordCategory, + wallet::{base_wallet::record_category::RecordCategory, indy::IndySdkWallet}, }; use credx::{ anoncreds_clsignatures::{bn::BigNumber, LinkSecret as ClLinkSecret}, @@ -66,7 +88,7 @@ mod tests { }; use serde_json::json; use vdrtools::{ - types::domain::wallet::{Config, Credentials, KeyDerivationMethod}, + types::domain::wallet::{Config, Credentials, IndyRecord, KeyDerivationMethod}, Locator, WalletHandle, }; @@ -249,8 +271,11 @@ mod tests { .await .unwrap(); + let src_wallet = IndySdkWallet::new(src_wallet_handle); + let dest_wallet = IndySdkWallet::new(dest_wallet_handle); + // Migrate the records - migrate_wallet(src_wallet_handle, dest_wallet_handle, migrate_any_record) + migrate_wallet(&src_wallet, &dest_wallet, migrate_any_record) .await .unwrap(); diff --git a/aries/wrappers/uniffi-aries-vcx/core/Cargo.toml b/aries/wrappers/uniffi-aries-vcx/core/Cargo.toml index c0caec0466..78b2c2991a 100644 --- a/aries/wrappers/uniffi-aries-vcx/core/Cargo.toml +++ b/aries/wrappers/uniffi-aries-vcx/core/Cargo.toml @@ -15,10 +15,14 @@ path = "uniffi-bindgen.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["vdrtools_wallet"] +vdrtools_wallet = ["aries_vcx/vdrtools_wallet"] +askar_wallet = ["aries_vcx/askar_wallet"] + [dependencies] uniffi = { version = "0.23.0", features = ["cli"] } aries_vcx = { path = "../../../aries_vcx", features = [ - "vdrtools_wallet", "credx", ] } tokio = { version = "1.24.1", features = ["rt-multi-thread"] } diff --git a/aries/wrappers/uniffi-aries-vcx/core/build.rs b/aries/wrappers/uniffi-aries-vcx/core/build.rs index 702c6cc8a2..409190cb72 100644 --- a/aries/wrappers/uniffi-aries-vcx/core/build.rs +++ b/aries/wrappers/uniffi-aries-vcx/core/build.rs @@ -1,3 +1,7 @@ fn main() { + #[cfg(feature = "vdrtools_wallet")] uniffi::generate_scaffolding("./src/vcx.udl").unwrap(); + + #[cfg(feature = "askar_wallet")] + uniffi::generate_scaffolding("./src/vcx_askar.udl").unwrap(); } diff --git a/aries/wrappers/uniffi-aries-vcx/core/src/core/profile.rs b/aries/wrappers/uniffi-aries-vcx/core/src/core/profile.rs deleted file mode 100644 index 0c0f44814a..0000000000 --- a/aries/wrappers/uniffi-aries-vcx/core/src/core/profile.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::sync::Arc; - -use aries_vcx::{ - aries_vcx_core::{ - anoncreds::{base_anoncreds::BaseAnonCreds, credx_anoncreds::IndyCredxAnonCreds}, - ledger::{ - base_ledger::TxnAuthrAgrmtOptions, - indy_vdr_ledger::{indyvdr_build_ledger_read, IndyVdrLedgerRead}, - request_submitter::vdr_ledger::{IndyVdrLedgerPool, IndyVdrSubmitter}, - response_cacher::in_memory::{InMemoryResponseCacher, InMemoryResponseCacherConfig}, - }, - wallet::indy::{wallet::create_and_open_wallet, IndySdkWallet, WalletConfig}, - PoolConfig, - }, - errors::error::{AriesVcxError, AriesVcxErrorKind, VcxResult}, -}; - -use super::logging::enable_logging; -use crate::{errors::error::VcxUniFFIResult, runtime::block_on}; - -#[derive(Debug)] -pub struct UniffiProfile { - wallet: IndySdkWallet, - anoncreds: IndyCredxAnonCreds, - ledger_read: IndyVdrLedgerRead, -} - -impl UniffiProfile { - pub fn ledger_read(&self) -> &IndyVdrLedgerRead { - &self.ledger_read - } - - pub fn anoncreds(&self) -> &IndyCredxAnonCreds { - &self.anoncreds - } - - pub fn wallet(&self) -> &IndySdkWallet { - &self.wallet - } - - pub fn update_taa_configuration(&self, _taa_options: TxnAuthrAgrmtOptions) -> VcxResult<()> { - Err(AriesVcxError::from_msg( - AriesVcxErrorKind::ActionNotSupported, - "update_taa_configuration no implemented for VdrtoolsProfile", - )) - } -} - -pub struct ProfileHolder { - pub(crate) inner: UniffiProfile, -} - -pub fn new_indy_profile( - wallet_config: WalletConfig, - genesis_file_path: String, -) -> VcxUniFFIResult> { - // Enable android logging - enable_logging(); - - block_on(async { - let wh = create_and_open_wallet(&wallet_config).await?; - let wallet = IndySdkWallet::new(wh); - - let anoncreds = IndyCredxAnonCreds; - - anoncreds - .prover_create_link_secret(&wallet, &"main".to_string()) - .await - .ok(); - - let indy_vdr_config = PoolConfig::default(); - let cache_config = InMemoryResponseCacherConfig::builder() - .ttl(std::time::Duration::from_secs(60)) - .capacity(1000)? - .build(); - let ledger_pool = IndyVdrLedgerPool::new(genesis_file_path, indy_vdr_config, vec![])?; - let request_submitter = IndyVdrSubmitter::new(ledger_pool); - let ledger_read = indyvdr_build_ledger_read(request_submitter, cache_config)?; - let profile = UniffiProfile { - anoncreds: IndyCredxAnonCreds, - wallet, - ledger_read, - }; - - Ok(Arc::new(ProfileHolder { inner: profile })) - }) -} diff --git a/aries/wrappers/uniffi-aries-vcx/core/src/core/profile/askar.rs b/aries/wrappers/uniffi-aries-vcx/core/src/core/profile/askar.rs new file mode 100644 index 0000000000..ad8d69e76d --- /dev/null +++ b/aries/wrappers/uniffi-aries-vcx/core/src/core/profile/askar.rs @@ -0,0 +1,61 @@ +use std::sync::Arc; + +use aries_vcx::aries_vcx_core::{ + anoncreds::{base_anoncreds::BaseAnonCreds, credx_anoncreds::IndyCredxAnonCreds}, + ledger::{ + indy_vdr_ledger::{indyvdr_build_ledger_read, IndyVdrLedgerRead}, + request_submitter::vdr_ledger::{IndyVdrLedgerPool, IndyVdrSubmitter}, + response_cacher::in_memory::{InMemoryResponseCacher, InMemoryResponseCacherConfig}, + }, + wallet::{ + askar::{askar_wallet_config::AskarWalletConfig, AskarWallet}, + base_wallet::ManageWallet, + }, + PoolConfig, +}; + +use crate::{ + core::logging::enable_logging, errors::error::VcxUniFFIResult, runtime::block_on, ProfileHolder, +}; + +#[derive(Debug)] +pub struct UniffiProfile { + pub wallet: AskarWallet, + pub anoncreds: IndyCredxAnonCreds, + pub ledger_read: IndyVdrLedgerRead, +} + +pub fn new_indy_profile( + wallet_config: AskarWalletConfig, + genesis_file_path: String, +) -> VcxUniFFIResult> { + // Enable android logging + enable_logging(); + + block_on(async { + let wallet = wallet_config.create_wallet().await?; + + let anoncreds = IndyCredxAnonCreds; + + anoncreds + .prover_create_link_secret(&wallet, &"main".to_string()) + .await + .ok(); + + let indy_vdr_config = PoolConfig::default(); + let cache_config = InMemoryResponseCacherConfig::builder() + .ttl(std::time::Duration::from_secs(60)) + .capacity(1000)? + .build(); + let ledger_pool = IndyVdrLedgerPool::new(genesis_file_path, indy_vdr_config, vec![])?; + let request_submitter = IndyVdrSubmitter::new(ledger_pool); + let ledger_read = indyvdr_build_ledger_read(request_submitter, cache_config)?; + let profile = UniffiProfile { + anoncreds: IndyCredxAnonCreds, + wallet, + ledger_read, + }; + + Ok(Arc::new(ProfileHolder { inner: profile })) + }) +} diff --git a/aries/wrappers/uniffi-aries-vcx/core/src/core/profile/indy.rs b/aries/wrappers/uniffi-aries-vcx/core/src/core/profile/indy.rs new file mode 100644 index 0000000000..2de314aece --- /dev/null +++ b/aries/wrappers/uniffi-aries-vcx/core/src/core/profile/indy.rs @@ -0,0 +1,61 @@ +use std::sync::Arc; + +use aries_vcx::aries_vcx_core::{ + anoncreds::{base_anoncreds::BaseAnonCreds, credx_anoncreds::IndyCredxAnonCreds}, + ledger::{ + indy_vdr_ledger::{indyvdr_build_ledger_read, IndyVdrLedgerRead}, + request_submitter::vdr_ledger::{IndyVdrLedgerPool, IndyVdrSubmitter}, + response_cacher::in_memory::{InMemoryResponseCacher, InMemoryResponseCacherConfig}, + }, + wallet::{ + base_wallet::ManageWallet, + indy::{indy_wallet_config::IndyWalletConfig, IndySdkWallet}, + }, + PoolConfig, +}; + +use crate::{ + core::logging::enable_logging, errors::error::VcxUniFFIResult, runtime::block_on, ProfileHolder, +}; + +#[derive(Debug)] +pub struct UniffiProfile { + pub wallet: IndySdkWallet, + pub anoncreds: IndyCredxAnonCreds, + pub ledger_read: IndyVdrLedgerRead, +} + +pub fn new_indy_profile( + wallet_config: IndyWalletConfig, + genesis_file_path: String, +) -> VcxUniFFIResult> { + // Enable android logging + enable_logging(); + + block_on(async { + let wallet = wallet_config.create_wallet().await?; + + let anoncreds = IndyCredxAnonCreds; + + anoncreds + .prover_create_link_secret(&wallet, &"main".to_string()) + .await + .ok(); + + let indy_vdr_config = PoolConfig::default(); + let cache_config = InMemoryResponseCacherConfig::builder() + .ttl(std::time::Duration::from_secs(60)) + .capacity(1000)? + .build(); + let ledger_pool = IndyVdrLedgerPool::new(genesis_file_path, indy_vdr_config, vec![])?; + let request_submitter = IndyVdrSubmitter::new(ledger_pool); + let ledger_read = indyvdr_build_ledger_read(request_submitter, cache_config)?; + let profile = UniffiProfile { + anoncreds: IndyCredxAnonCreds, + wallet, + ledger_read, + }; + + Ok(Arc::new(ProfileHolder { inner: profile })) + }) +} diff --git a/aries/wrappers/uniffi-aries-vcx/core/src/core/profile/mod.rs b/aries/wrappers/uniffi-aries-vcx/core/src/core/profile/mod.rs new file mode 100644 index 0000000000..493586bc84 --- /dev/null +++ b/aries/wrappers/uniffi-aries-vcx/core/src/core/profile/mod.rs @@ -0,0 +1,58 @@ +use aries_vcx::{ + aries_vcx_core::{ + anoncreds::credx_anoncreds::IndyCredxAnonCreds, + ledger::{ + base_ledger::TxnAuthrAgrmtOptions, indy_vdr_ledger::IndyVdrLedgerRead, + request_submitter::vdr_ledger::IndyVdrSubmitter, + response_cacher::in_memory::InMemoryResponseCacher, + }, + }, + errors::error::{AriesVcxError, AriesVcxErrorKind, VcxResult}, +}; + +#[cfg(feature = "vdrtools_wallet")] +pub mod indy; +#[cfg(feature = "vdrtools_wallet")] +use aries_vcx::aries_vcx_core::wallet::indy::IndySdkWallet; +#[cfg(feature = "vdrtools_wallet")] +pub use indy as profile; + +#[cfg(feature = "askar_wallet")] +pub mod askar; +#[cfg(feature = "askar_wallet")] +use aries_vcx::aries_vcx_core::wallet::askar::AskarWallet; +#[cfg(feature = "askar_wallet")] +pub use askar as profile; + +use crate::profile::UniffiProfile; + +impl UniffiProfile { + pub fn ledger_read(&self) -> &IndyVdrLedgerRead { + &self.ledger_read + } + + pub fn anoncreds(&self) -> &IndyCredxAnonCreds { + &self.anoncreds + } + + #[cfg(feature = "vdrtools_wallet")] + pub fn wallet(&self) -> &IndySdkWallet { + &self.wallet + } + + #[cfg(feature = "askar_wallet")] + pub fn wallet(&self) -> &AskarWallet { + &self.wallet + } + + pub fn update_taa_configuration(&self, _taa_options: TxnAuthrAgrmtOptions) -> VcxResult<()> { + Err(AriesVcxError::from_msg( + AriesVcxErrorKind::ActionNotSupported, + "update_taa_configuration no implemented for VdrtoolsProfile", + )) + } +} + +pub struct ProfileHolder { + pub(crate) inner: UniffiProfile, +} diff --git a/aries/wrappers/uniffi-aries-vcx/core/src/core/unpack_message.rs b/aries/wrappers/uniffi-aries-vcx/core/src/core/unpack_message.rs index f78f1529aa..83f417b03a 100644 --- a/aries/wrappers/uniffi-aries-vcx/core/src/core/unpack_message.rs +++ b/aries/wrappers/uniffi-aries-vcx/core/src/core/unpack_message.rs @@ -1,6 +1,8 @@ use std::sync::Arc; -use aries_vcx::aries_vcx_core::wallet::{base_wallet::DidWallet, structs_io::UnpackMessageOutput}; +use aries_vcx::aries_vcx_core::wallet::{ + base_wallet::did_wallet::DidWallet, structs_io::UnpackMessageOutput, +}; use super::profile::ProfileHolder; use crate::{errors::error::VcxUniFFIResult, runtime::block_on}; diff --git a/aries/wrappers/uniffi-aries-vcx/core/src/lib.rs b/aries/wrappers/uniffi-aries-vcx/core/src/lib.rs index da63c32708..1c4e0f454b 100644 --- a/aries/wrappers/uniffi-aries-vcx/core/src/lib.rs +++ b/aries/wrappers/uniffi-aries-vcx/core/src/lib.rs @@ -1,16 +1,26 @@ +#[cfg(feature = "vdrtools_wallet")] uniffi::include_scaffolding!("vcx"); +#[cfg(feature = "askar_wallet")] +uniffi::include_scaffolding!("vcx_askar"); + pub mod core; pub mod errors; pub mod handlers; pub mod runtime; -use aries_vcx::{ - aries_vcx_core::wallet::indy::WalletConfig, protocols::connection::pairwise_info::PairwiseInfo, +#[cfg(feature = "askar_wallet")] +use aries_vcx::aries_vcx_core::wallet::askar::{ + askar_wallet_config::AskarWalletConfig, + key_method::{ArgonLevel, AskarKdfMethod, KeyMethod}, }; +#[cfg(feature = "vdrtools_wallet")] +use aries_vcx::aries_vcx_core::wallet::indy::indy_wallet_config::IndyWalletConfig; +use aries_vcx::protocols::connection::pairwise_info::PairwiseInfo; use handlers::{connection::*, holder::*}; use crate::{ core::{anoncreds::*, profile::*, unpack_message::*}, errors::error::*, + profile::new_indy_profile, }; diff --git a/aries/wrappers/uniffi-aries-vcx/core/src/vcx.udl b/aries/wrappers/uniffi-aries-vcx/core/src/vcx.udl index e7b94bd765..e55abbee5d 100644 --- a/aries/wrappers/uniffi-aries-vcx/core/src/vcx.udl +++ b/aries/wrappers/uniffi-aries-vcx/core/src/vcx.udl @@ -2,7 +2,7 @@ interface ProfileHolder { }; -dictionary WalletConfig { +dictionary IndyWalletConfig { string wallet_name; string wallet_key; string wallet_key_derivation; @@ -158,7 +158,7 @@ enum VcxUniFFIError { namespace vcx { [Throws=VcxUniFFIError] - ProfileHolder new_indy_profile(WalletConfig wallet_config, string genesis_file_path); + ProfileHolder new_indy_profile(IndyWalletConfig wallet_config, string genesis_file_path); [Throws=VcxUniFFIError] Connection create_inviter(ProfileHolder profile); diff --git a/aries/wrappers/uniffi-aries-vcx/core/src/vcx_askar.udl b/aries/wrappers/uniffi-aries-vcx/core/src/vcx_askar.udl new file mode 100644 index 0000000000..fd81c89b91 --- /dev/null +++ b/aries/wrappers/uniffi-aries-vcx/core/src/vcx_askar.udl @@ -0,0 +1,196 @@ +interface ProfileHolder { + +}; + +enum ArgonLevel { + "Interactive", + "Moderate", +}; + +[Enum] +interface AskarKdfMethod { + Argon2i(ArgonLevel inner); +}; + +[Enum] +interface KeyMethod { + DeriveKey(AskarKdfMethod inner); + RawKey(); + Unprotected(); +}; + +dictionary AskarWalletConfig { + string db_url; + KeyMethod key_method; + string pass_key; + string profile; +}; + +dictionary ConnectionState { + ConnectionRole role; + ConnectionProtocolState protocol_state; +}; + +enum ConnectionRole { + "Invitee", + "Inviter", +}; + +enum ConnectionProtocolState { + "Initial", + "Invited", + "Requested", + "Responded", + "Completed", +}; + +dictionary PairwiseInfo { + string pw_did; + string pw_vk; +}; + +dictionary UnpackMessage { + string message; + string recipient_verkey; + string? sender_verkey; +}; + +interface Connection { + [Throws=VcxUniFFIError] + ConnectionState get_state(); + + [Throws=VcxUniFFIError] + PairwiseInfo pairwise_info(); + + [Throws=VcxUniFFIError] + void accept_invitation(ProfileHolder profile, string invitation); + + [Throws=VcxUniFFIError] + void handle_request(ProfileHolder profile, string request, string service_endpoint, sequence routing_keys); + + [Throws=VcxUniFFIError] + void handle_response(ProfileHolder profile, string response); + + [Throws=VcxUniFFIError] + void send_request(ProfileHolder profile, string service_endpoint, sequence routing_keys); + + [Throws=VcxUniFFIError] + void send_response(ProfileHolder profile); + + [Throws=VcxUniFFIError] + void send_ack(ProfileHolder profile); + + [Throws=VcxUniFFIError] + void send_message(ProfileHolder profile, string message); +}; + +interface Holder { + [Throws=VcxUniFFIError] + void set_proposal(string credential_proposal); + + [Throws=VcxUniFFIError] + void prepare_credential_request(ProfileHolder profile, string my_pw_did); + + [Throws=VcxUniFFIError] + string get_msg_credential_request(); + + [Throws=VcxUniFFIError] + string decline_offer(string? comment); + + [Throws=VcxUniFFIError] + void process_credential(ProfileHolder profile, string credential); + + [Throws=VcxUniFFIError] + boolean is_terminal_state(); + + [Throws=VcxUniFFIError] + HolderState get_state(); + + [Throws=VcxUniFFIError] + string get_source_id(); + + [Throws=VcxUniFFIError] + string get_credential(); + + [Throws=VcxUniFFIError] + string get_attributes(); + + [Throws=VcxUniFFIError] + string get_attachment(); + + [Throws=VcxUniFFIError] + string get_offer(); + + [Throws=VcxUniFFIError] + string get_tails_location(); + + [Throws=VcxUniFFIError] + string get_tails_hash(); + + [Throws=VcxUniFFIError] + string get_rev_reg_id(); + + [Throws=VcxUniFFIError] + string get_cred_id(); + + [Throws=VcxUniFFIError] + string get_thread_id(); + + [Throws=VcxUniFFIError] + boolean is_revokable(ProfileHolder profile); + + [Throws=VcxUniFFIError] + boolean is_revoked(ProfileHolder profile); + + [Throws=VcxUniFFIError] + u32 get_cred_rev_id(ProfileHolder profile); + + [Throws=VcxUniFFIError] + string get_problem_report(); + + [Throws=VcxUniFFIError] + string? get_final_message(); +}; + +enum HolderState { + "Initial", + "ProposalSet", + "OfferReceived", + "RequestSet", + "Finished", + "Failed" +}; + +[Error] +enum VcxUniFFIError { + "AriesVcxError", + "SerializationError", + "InternalError", + "StringParseError" +}; + +namespace vcx { + [Throws=VcxUniFFIError] + ProfileHolder new_indy_profile(AskarWalletConfig wallet_config, string genesis_file_path); + + [Throws=VcxUniFFIError] + Connection create_inviter(ProfileHolder profile); + + [Throws=VcxUniFFIError] + Connection create_invitee(ProfileHolder profile); + + [Throws=VcxUniFFIError] + UnpackMessage unpack_message(ProfileHolder profile, string packed_msg); + + [Throws=VcxUniFFIError] + Holder create(string source_id); + + [Throws=VcxUniFFIError] + Holder create_from_offer(string source_id, string offer_message); + + [Throws=VcxUniFFIError] + Holder create_with_proposal(string source_id, string propose_credential); + + [Throws=VcxUniFFIError] + string get_credentials(ProfileHolder profile); +}; diff --git a/aries/wrappers/vcx-napi-rs/Cargo.toml b/aries/wrappers/vcx-napi-rs/Cargo.toml index 7edeb4557d..b3c2df83be 100644 --- a/aries/wrappers/vcx-napi-rs/Cargo.toml +++ b/aries/wrappers/vcx-napi-rs/Cargo.toml @@ -11,6 +11,11 @@ path = "src/lib.rs" crate-type = ["cdylib"] doctest = false +[features] +default = ["vdrtools_wallet"] +askar_wallet = ["libvcx_core/askar_wallet"] +vdrtools_wallet = ["libvcx_core/vdrtools_wallet"] + [dependencies] libvcx_core = { path = "../../misc/legacy/libvcx_core" } wallet_migrator = { path = "../../misc/wallet_migrator" } @@ -20,6 +25,8 @@ napi-derive = { version = "2.10.1" } uuid = { version = "1.5.0", default-features = false, features = ["v4"] } chrono = "0.4.23" libvcx_logger = { path = "../../misc/legacy/libvcx_logger" } +serde = { version = "1.0.159", features = ["derive"] } +serde_json = "1.0.95" [build-dependencies] napi-build = "2.0.1" diff --git a/aries/wrappers/vcx-napi-rs/src/api/mod.rs b/aries/wrappers/vcx-napi-rs/src/api/mod.rs index 741d61ee88..50b4802843 100644 --- a/aries/wrappers/vcx-napi-rs/src/api/mod.rs +++ b/aries/wrappers/vcx-napi-rs/src/api/mod.rs @@ -8,6 +8,7 @@ pub mod issuer_credential; pub mod ledger; pub mod logging; pub mod mediated_connection; +pub mod napi_wallet; pub mod out_of_band; pub mod out_of_band_receiver; pub mod out_of_band_sender; diff --git a/aries/wrappers/vcx-napi-rs/src/api/napi_wallet/askar.rs b/aries/wrappers/vcx-napi-rs/src/api/napi_wallet/askar.rs new file mode 100644 index 0000000000..cd3e9c20fd --- /dev/null +++ b/aries/wrappers/vcx-napi-rs/src/api/napi_wallet/askar.rs @@ -0,0 +1,21 @@ +use std::{ops::Deref, sync::Arc}; + +use libvcx_core::aries_vcx::aries_vcx_core::wallet::askar::AskarWallet; +use napi_derive::napi; + +#[napi] +pub struct NapiWallet(Arc); + +impl NapiWallet { + pub fn new(wallet: Arc) -> Self { + Self(wallet) + } +} + +impl Deref for NapiWallet { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/aries/wrappers/vcx-napi-rs/src/api/napi_wallet/indy.rs b/aries/wrappers/vcx-napi-rs/src/api/napi_wallet/indy.rs new file mode 100644 index 0000000000..4ec51cb2eb --- /dev/null +++ b/aries/wrappers/vcx-napi-rs/src/api/napi_wallet/indy.rs @@ -0,0 +1,21 @@ +use std::{ops::Deref, sync::Arc}; + +use libvcx_core::aries_vcx::aries_vcx_core::wallet::indy::IndySdkWallet; +use napi_derive::napi; + +#[napi] +pub struct NapiWallet(Arc); + +impl NapiWallet { + pub fn new(wallet: Arc) -> Self { + Self(wallet) + } +} + +impl Deref for NapiWallet { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/aries/wrappers/vcx-napi-rs/src/api/napi_wallet/mod.rs b/aries/wrappers/vcx-napi-rs/src/api/napi_wallet/mod.rs new file mode 100644 index 0000000000..e86e5ff6e5 --- /dev/null +++ b/aries/wrappers/vcx-napi-rs/src/api/napi_wallet/mod.rs @@ -0,0 +1,9 @@ +#[cfg(feature = "askar_wallet")] +pub mod askar; +#[cfg(feature = "askar_wallet")] +pub use askar as napi_wallet; + +#[cfg(feature = "vdrtools_wallet")] +pub mod indy; +#[cfg(feature = "vdrtools_wallet")] +pub use indy as napi_wallet; diff --git a/aries/wrappers/vcx-napi-rs/src/api/wallet.rs b/aries/wrappers/vcx-napi-rs/src/api/wallet.rs index d089b46ada..1b4867a210 100644 --- a/aries/wrappers/vcx-napi-rs/src/api/wallet.rs +++ b/aries/wrappers/vcx-napi-rs/src/api/wallet.rs @@ -1,51 +1,68 @@ +#[cfg(feature = "askar_wallet")] +use libvcx_core::aries_vcx::aries_vcx_core::wallet::askar::askar_wallet_config::AskarWalletConfig; +#[cfg(feature = "vdrtools_wallet")] +use libvcx_core::aries_vcx::aries_vcx_core::wallet::indy::indy_wallet_config::IndyWalletConfig; use libvcx_core::{ - api_vcx::api_global::{ledger, wallet}, - aries_vcx::aries_vcx_core::wallet::indy::{ - wallet::delete_wallet, RestoreWalletConfigs, WalletConfig, + api_vcx::api_global::{ + ledger, + wallet::{self}, }, + aries_vcx::aries_vcx_core::wallet::base_wallet::ManageWallet, errors::error::{LibvcxError, LibvcxErrorKind}, - serde_json, - serde_json::json, + serde_json::{self, json}, }; use napi::bindgen_prelude::Buffer; use napi_derive::napi; +use super::napi_wallet::napi_wallet::NapiWallet; use crate::error::to_napi_err; -#[napi] -pub async fn wallet_open_as_main(wallet_config: String) -> napi::Result { - let wallet_config = serde_json::from_str::(&wallet_config) +#[cfg(feature = "vdrtools_wallet")] +fn parse_wallet_config(config: &str) -> napi::Result { + serde_json::from_str::(config) .map_err(|err| { LibvcxError::from_msg( LibvcxErrorKind::InvalidConfiguration, format!("Serialization error: {:?}", err), ) }) - .map_err(to_napi_err)?; - let handle = wallet::open_as_main_wallet(&wallet_config) - .await - .map_err(to_napi_err)?; - Ok(handle.0) + .map_err(to_napi_err) } -#[napi] -pub async fn wallet_create_main(wallet_config: String) -> napi::Result<()> { - let wallet_config = serde_json::from_str::(&wallet_config) +#[cfg(feature = "askar_wallet")] +fn parse_wallet_config(config: &str) -> napi::Result { + serde_json::from_str::(config) .map_err(|err| { LibvcxError::from_msg( LibvcxErrorKind::InvalidConfiguration, format!("Serialization error: {:?}", err), ) }) + .map_err(to_napi_err) +} + +#[napi] +pub async fn wallet_open_as_main(wallet_config: String) -> napi::Result { + let wallet_config = parse_wallet_config(&wallet_config)?; + let wallet = wallet::wallet::open_as_main_wallet(&wallet_config) + .await .map_err(to_napi_err)?; - wallet::create_main_wallet(&wallet_config) + Ok(NapiWallet::new(wallet)) +} + +#[napi] +pub async fn wallet_create_main(wallet_config: String) -> napi::Result<()> { + let wallet_config = parse_wallet_config(&wallet_config)?; + wallet::wallet::create_main_wallet(&wallet_config) .await .map_err(to_napi_err) } #[napi] pub async fn wallet_close_main() -> napi::Result<()> { - wallet::close_main_wallet().await.map_err(to_napi_err) + wallet::wallet::close_main_wallet() + .await + .map_err(to_napi_err) } #[napi] @@ -75,7 +92,7 @@ pub async fn create_and_store_did(seed: Option) -> napi::Result #[napi] pub async fn wallet_import(config: String) -> napi::Result<()> { - let config = serde_json::from_str::(&config) + let config = serde_json::from_str(&config) .map_err(|err| { LibvcxError::from_msg( LibvcxErrorKind::InvalidConfiguration, @@ -83,7 +100,9 @@ pub async fn wallet_import(config: String) -> napi::Result<()> { ) }) .map_err(to_napi_err)?; - wallet::wallet_import(&config).await.map_err(to_napi_err) + wallet::wallet::wallet_import(&config) + .await + .map_err(to_napi_err) } #[napi] @@ -95,32 +114,19 @@ pub async fn wallet_export(path: String, backup_key: String) -> napi::Result<()> #[napi] pub async fn wallet_migrate(wallet_config: String) -> napi::Result<()> { - let wallet_config = serde_json::from_str(&wallet_config) - .map_err(|err| { - LibvcxError::from_msg( - LibvcxErrorKind::InvalidConfiguration, - format!("Serialization error: {:?}", err), - ) - }) - .map_err(to_napi_err)?; + let wallet_config = parse_wallet_config(&wallet_config)?; - wallet::wallet_migrate(&wallet_config) + wallet::wallet::wallet_migrate(&wallet_config) .await .map_err(|e| napi::Error::from_reason(e.to_string())) } #[napi] pub async fn wallet_delete(wallet_config: String) -> napi::Result<()> { - let wallet_config = serde_json::from_str(&wallet_config) - .map_err(|err| { - LibvcxError::from_msg( - LibvcxErrorKind::InvalidConfiguration, - format!("Serialization error: {:?}", err), - ) - }) - .map_err(to_napi_err)?; + let wallet_config = parse_wallet_config(&wallet_config)?; - delete_wallet(&wallet_config) + wallet_config + .delete_wallet() .await .map_err(|e| napi::Error::from_reason(e.to_string())) } diff --git a/justfile b/justfile index 839e15d1ed..ba94ed6076 100644 --- a/justfile +++ b/justfile @@ -7,8 +7,8 @@ fmt: fmt-check: cargo +nightly-2023-05-08 fmt --check -clippy-workspace: - cargo clippy --examples --tests --all-features +clippy-workspace wallet: + cargo clippy --examples --tests --no-default-features -F credx,anoncreds,vdr_proxy_ledger,legacy_proof,{{wallet}} clippy-aries-vcx features: cargo clippy -p aries_vcx --features legacy_proof --features {{features}} --no-default-features @@ -55,8 +55,8 @@ test-integration-aries-vcx-mysql test_name="": test-integration-aries-vcx-vdrproxy test_name="": cargo test --manifest-path="aries/aries_vcx/Cargo.toml" -F vdr_proxy_ledger,credx -- --ignored {{test_name}} -test-integration-libvcx test_name="": - RUST_TEST_THREADS=1 cargo test --manifest-path="aries/misc/legacy/libvcx_core/Cargo.toml" -- --include-ignored {{test_name}} +test-integration-libvcx wallet test_name="": + RUST_TEST_THREADS=1 cargo test --manifest-path="aries/misc/legacy/libvcx_core/Cargo.toml" -F {{wallet}} -- --include-ignored {{test_name}} test-integration-did-crate test_name="": 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 "*"