From 2a79edd94349e7ff833ba92e78761cfb8ceeb8f8 Mon Sep 17 00:00:00 2001 From: Thomas Kim Date: Fri, 15 May 2020 17:18:53 +0900 Subject: [PATCH 1/3] Developed a delete credential API Signed-off-by: Thomas Kim --- vcx/libvcx/src/api/credential.rs | 44 +++++++++++++++++++ vcx/libvcx/src/credential.rs | 21 +++++++++ vcx/libvcx/src/utils/libindy/anoncreds.rs | 8 ++++ vcx/libvcx/src/v3/handlers/issuance/holder.rs | 18 +++++++- vcx/libvcx/src/v3/handlers/issuance/mod.rs | 4 ++ 5 files changed, 94 insertions(+), 1 deletion(-) diff --git a/vcx/libvcx/src/api/credential.rs b/vcx/libvcx/src/api/credential.rs index cc8147779e..c6c86430c3 100644 --- a/vcx/libvcx/src/api/credential.rs +++ b/vcx/libvcx/src/api/credential.rs @@ -240,6 +240,50 @@ pub extern fn vcx_get_credential(command_handle: CommandHandle, error::SUCCESS.code_num } +/// Delete a Credential from the wallet and release its handle. +/// +/// # Params +/// command_handle: command handle to map callback to user context. +/// +/// credential_handle: handle of the credential to delete. +/// +/// cb: Callback that provides feedback of the api call. +/// +/// # Returns +/// Error code as a u32 +#[no_mangle] +#[allow(unused_assignments)] +pub extern fn vcx_delete_credential(command_handle: CommandHandle, + credential_handle: u32, + cb: Option) -> u32 { + info!("vcx_delete_credential >>>"); + + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + if !credential::is_valid_handle(credential_handle) { + return VcxError::from(VcxErrorKind::InvalidCredentialHandle).into() + } + + trace!("vcx_connection_delete_connection(command_handle: {}, credential_handle: {})", command_handle, credential_handle); + spawn(move || { + match credential::delete_credential(credential_handle) { + Ok(_) => { + trace!("vcx_credential_delete_credential_cb(command_handle: {}, rc: {})", command_handle, error::SUCCESS.message); + cb(command_handle, error::SUCCESS.code_num); + } + Err(e) => { + trace!("vcx_credential_delete_credential_cb(command_handle: {}, rc: {})", command_handle, e); + cb(command_handle, e.into()); + } + } + + Ok(()) + }); + + error::SUCCESS.code_num +} + /// Create a Credential object based off of a known message id for a given connection. /// /// #Params diff --git a/vcx/libvcx/src/credential.rs b/vcx/libvcx/src/credential.rs index e41c2c762d..fe170df2eb 100644 --- a/vcx/libvcx/src/credential.rs +++ b/vcx/libvcx/src/credential.rs @@ -530,6 +530,27 @@ pub fn get_credential(handle: u32) -> VcxResult { }) } +pub fn delete_credential(handle: u32) -> VcxResult { + HANDLE_MAP.get_mut(handle, |credential| { + match credential { + Credentials::Pending(_) => { + Err(VcxError::from_msg(VcxErrorKind::InvalidCredentialHandle, "Cannot delete credential for Pending object")) + } + Credentials::V1(_) => { + Err(VcxError::from(VcxErrorKind::NotReady)) + } + Credentials::V3(ref credential) => { + credential.delete_credential()?; + Ok(error::SUCCESS.code_num) + } + } + }) + .map(|_| error::SUCCESS.code_num) + .or(Err(VcxError::from(VcxErrorKind::InvalidCredentialHandle))) + .and(release(handle)) + .and_then(|_| Ok(error::SUCCESS.code_num)) +} + pub fn get_payment_txn(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { match obj { diff --git a/vcx/libvcx/src/utils/libindy/anoncreds.rs b/vcx/libvcx/src/utils/libindy/anoncreds.rs index 324f401a76..6ad04f405e 100644 --- a/vcx/libvcx/src/utils/libindy/anoncreds.rs +++ b/vcx/libvcx/src/utils/libindy/anoncreds.rs @@ -248,6 +248,14 @@ pub fn libindy_prover_store_credential(cred_id: Option<&str>, .map_err(VcxError::from) } +pub fn libindy_prover_delete_credential(cred_id: &str) -> VcxResult<()>{ + + anoncreds::prover_delete_credential(get_wallet_handle(), + cred_id) + .wait() + .map_err(VcxError::from) +} + pub fn libindy_prover_create_master_secret(master_secret_id: &str) -> VcxResult { if settings::indy_mocks_enabled() { return Ok(settings::DEFAULT_LINK_SECRET_ALIAS.to_string()); } diff --git a/vcx/libvcx/src/v3/handlers/issuance/holder.rs b/vcx/libvcx/src/v3/handlers/issuance/holder.rs index 27dc4d344e..441774228c 100644 --- a/vcx/libvcx/src/v3/handlers/issuance/holder.rs +++ b/vcx/libvcx/src/v3/handlers/issuance/holder.rs @@ -11,7 +11,7 @@ use v3::messages::a2a::A2AMessage; use v3::messages::status::Status; use connection; -use utils::libindy::anoncreds::{self, libindy_prover_store_credential}; +use utils::libindy::anoncreds::{self, libindy_prover_store_credential, libindy_prover_delete_credential}; use error::prelude::*; use std::collections::HashMap; @@ -199,6 +199,16 @@ impl HolderSM { _ => Err(VcxError::from_msg(VcxErrorKind::NotReady, "Cannot get credential: Credential Issuance is not finished yet")) } } + + pub fn delete_credential(&self) -> VcxResult<()> { + match self.state { + HolderState::Finished(ref state) => { + let cred_id = state.cred_id.clone().ok_or(VcxError::from_msg(VcxErrorKind::InvalidState, "Cannot get credential: Credential Id not found"))?; + _delete_credential(&cred_id) + } + _ => Err(VcxError::from_msg(VcxErrorKind::NotReady, "Cannot delete credential: Credential Issuance is not finished yet")) + } + } } fn _parse_cred_def_from_cred_offer(cred_offer: &str) -> VcxResult { @@ -244,6 +254,12 @@ fn _store_credential(credential: &Credential, rev_reg_def_json.as_ref().map(String::as_str)) } +fn _delete_credential(cred_id: &str) -> VcxResult<()> { + trace!("Holder::_delete_credential >>>"); + + libindy_prover_delete_credential(cred_id) +} + fn _make_credential_request(conn_handle: u32, offer: &CredentialOffer) -> VcxResult<(CredentialRequest, String, String)> { trace!("Holder::_make_credential_request >>> conn_handle: {:?}, offer: {:?}", conn_handle, offer); diff --git a/vcx/libvcx/src/v3/handlers/issuance/mod.rs b/vcx/libvcx/src/v3/handlers/issuance/mod.rs index 9fbed3faf3..192eb0e1bd 100644 --- a/vcx/libvcx/src/v3/handlers/issuance/mod.rs +++ b/vcx/libvcx/src/v3/handlers/issuance/mod.rs @@ -122,6 +122,10 @@ impl Holder { self.holder_sm.get_credential() } + pub fn delete_credential(&self) -> VcxResult<()> { + self.holder_sm.delete_credential() + } + pub fn get_credential_status(&self) -> VcxResult { Ok(self.holder_sm.credential_status()) } From 83f0f6349dda65ef1a68a5918cf516d5d39ab4d0 Mon Sep 17 00:00:00 2001 From: Thomas Kim Date: Fri, 15 May 2020 17:19:43 +0900 Subject: [PATCH 2/3] Implemented the Java wrapper for the API "delete credential" Signed-off-by: Thomas Kim --- .../main/java/com/evernym/sdk/vcx/LibVcx.java | 3 +++ .../sdk/vcx/credential/CredentialApi.java | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/LibVcx.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/LibVcx.java index 580c75c646..3d159ca45e 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/LibVcx.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/LibVcx.java @@ -520,6 +520,9 @@ public interface API extends Library { /** Retrieve information about a stored credential in user's wallet, including credential id and the credential itself. */ public int vcx_get_credential(int command_handle, int credential_handle, Callback cb); + /** Delete a credential from the wallet and release it from memory. */ + public int vcx_delete_credential(int command_handle, int credential_handle, Callback cb); + /** * wallet object * diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credential/CredentialApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credential/CredentialApi.java index 9155f30dda..7363162702 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credential/CredentialApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credential/CredentialApi.java @@ -184,6 +184,31 @@ public static CompletableFuture getCredential( return future; } + private static Callback vcxDeleteCredentialCB = new Callback() { + @SuppressWarnings({"unused", "unchecked"}) + public void callback(int command_handle, int err) { + logger.debug("callback() called with: command_handle = [" + command_handle + "], err = [" + err + "]"); + CompletableFuture future = (CompletableFuture) removeFuture(command_handle); + if (!checkCallback(future,err)) return; + // returning empty string from here because we don't want to complete future with null + future.complete(""); + } + }; + + public static CompletableFuture deleteCredential( + int credentialHandle + ) throws VcxException { + ParamGuard.notNull(credentialHandle, "credentialHandle"); + logger.debug("deleteCredential() called with: credentialHandle = [" + credentialHandle + "]"); + CompletableFuture future = new CompletableFuture(); + int commandHandle = addFuture(future); + + int result = LibVcx.api.vcx_delete_credential(commandHandle, credentialHandle, vcxDeleteCredentialCB); + checkResult(result); + + return future; + } + private static Callback vcxCredentialUpdateStateCB = new Callback() { @SuppressWarnings({"unused", "unchecked"}) public void callback(int command_handle, int err, int state) { From 234e1d2516cba29665eeb3393f8c8d93e019ea92 Mon Sep 17 00:00:00 2001 From: Thomas Kim Date: Tue, 26 May 2020 18:40:30 +0900 Subject: [PATCH 3/3] Added more comments Signed-off-by: Thomas Kim --- vcx/libvcx/src/api/credential.rs | 10 ++++++---- vcx/libvcx/src/credential.rs | 10 +++++++++- vcx/libvcx/src/v3/handlers/issuance/holder.rs | 8 +++++--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/vcx/libvcx/src/api/credential.rs b/vcx/libvcx/src/api/credential.rs index c6c86430c3..6dd65cf274 100644 --- a/vcx/libvcx/src/api/credential.rs +++ b/vcx/libvcx/src/api/credential.rs @@ -247,7 +247,7 @@ pub extern fn vcx_get_credential(command_handle: CommandHandle, /// /// credential_handle: handle of the credential to delete. /// -/// cb: Callback that provides feedback of the api call. +/// cb: Callback that provides error status of delete credential request /// /// # Returns /// Error code as a u32 @@ -265,15 +265,17 @@ pub extern fn vcx_delete_credential(command_handle: CommandHandle, return VcxError::from(VcxErrorKind::InvalidCredentialHandle).into() } - trace!("vcx_connection_delete_connection(command_handle: {}, credential_handle: {})", command_handle, credential_handle); + let source_id = credential::get_source_id(credential_handle).unwrap_or_default(); + trace!("vcx_delete_credential(command_handle: {}, credential_handle: {}), source_id: {})", command_handle, credential_handle, source_id); + spawn(move || { match credential::delete_credential(credential_handle) { Ok(_) => { - trace!("vcx_credential_delete_credential_cb(command_handle: {}, rc: {})", command_handle, error::SUCCESS.message); + trace!("vcx_delete_credential_cb(command_handle: {}, rc: {}), credential_handle: {}, source_id: {})", command_handle, error::SUCCESS.message, credential_handle, source_id); cb(command_handle, error::SUCCESS.code_num); } Err(e) => { - trace!("vcx_credential_delete_credential_cb(command_handle: {}, rc: {})", command_handle, e); + trace!("vcx_delete_credential_cb(command_handle: {}, rc: {}), credential_handle: {}, source_id: {})", command_handle, e, credential_handle, source_id); cb(command_handle, e.into()); } } diff --git a/vcx/libvcx/src/credential.rs b/vcx/libvcx/src/credential.rs index fe170df2eb..84deee03ef 100644 --- a/vcx/libvcx/src/credential.rs +++ b/vcx/libvcx/src/credential.rs @@ -531,15 +531,23 @@ pub fn get_credential(handle: u32) -> VcxResult { } pub fn delete_credential(handle: u32) -> VcxResult { - HANDLE_MAP.get_mut(handle, |credential| { + let source_id = get_source_id(handle).unwrap_or_default(); + trace!("Credential::delete_credential >>> credential_handle: {}, source_id: {}", handle, source_id); + + HANDLE_MAP.get(handle, |credential| { match credential { Credentials::Pending(_) => { + trace!("Cannot delete credential for pending object"); Err(VcxError::from_msg(VcxErrorKind::InvalidCredentialHandle, "Cannot delete credential for Pending object")) } Credentials::V1(_) => { + // TODO: Implement + trace!("delete_credential for V1 is not implemented."); Err(VcxError::from(VcxErrorKind::NotReady)) } Credentials::V3(ref credential) => { + trace!("Deleting a credential: credential_handle {}, source_id {}", handle, source_id); + credential.delete_credential()?; Ok(error::SUCCESS.code_num) } diff --git a/vcx/libvcx/src/v3/handlers/issuance/holder.rs b/vcx/libvcx/src/v3/handlers/issuance/holder.rs index 441774228c..ad9c505ff5 100644 --- a/vcx/libvcx/src/v3/handlers/issuance/holder.rs +++ b/vcx/libvcx/src/v3/handlers/issuance/holder.rs @@ -201,12 +201,14 @@ impl HolderSM { } pub fn delete_credential(&self) -> VcxResult<()> { + trace!("Holder::delete_credential"); + match self.state { HolderState::Finished(ref state) => { - let cred_id = state.cred_id.clone().ok_or(VcxError::from_msg(VcxErrorKind::InvalidState, "Cannot get credential: Credential Id not found"))?; + let cred_id = state.cred_id.clone().ok_or(VcxError::from_msg(VcxErrorKind::InvalidState, "Cannot get credential: credential id not found"))?; _delete_credential(&cred_id) } - _ => Err(VcxError::from_msg(VcxErrorKind::NotReady, "Cannot delete credential: Credential Issuance is not finished yet")) + _ => Err(VcxError::from_msg(VcxErrorKind::NotReady, "Cannot delete credential: credential issuance is not finished yet")) } } } @@ -255,7 +257,7 @@ fn _store_credential(credential: &Credential, } fn _delete_credential(cred_id: &str) -> VcxResult<()> { - trace!("Holder::_delete_credential >>>"); + trace!("Holder::_delete_credential >>> cred_id: {}", cred_id); libindy_prover_delete_credential(cred_id) }