Skip to content

Commit

Permalink
Merge pull request hyperledger-archives#2172 from airoasis/feature/vc…
Browse files Browse the repository at this point in the history
…x-v3-delete-credential

LibVCX V3 (Aries) Delete Credential API
  • Loading branch information
mirgee authored Jun 24, 2020
2 parents 4595137 + c6f71cb commit c6c12ee
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 1 deletion.
46 changes: 46 additions & 0 deletions vcx/libvcx/src/api/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,52 @@ 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 error status of delete credential request
///
/// # 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<extern fn(
xcommand_handle: CommandHandle,
err: u32)>) -> 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()
}

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_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_delete_credential_cb(command_handle: {}, rc: {}), credential_handle: {}, source_id: {})", command_handle, e, credential_handle, source_id);
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
Expand Down
29 changes: 29 additions & 0 deletions vcx/libvcx/src/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,35 @@ pub fn get_credential(handle: u32) -> VcxResult<String> {
})
}

pub fn delete_credential(handle: u32) -> VcxResult<u32> {
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)
}
}
})
.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<PaymentTxn> {
HANDLE_MAP.get(handle, |obj| {
match obj {
Expand Down
8 changes: 8 additions & 0 deletions vcx/libvcx/src/utils/libindy/anoncreds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> {
if settings::indy_mocks_enabled() { return Ok(settings::DEFAULT_LINK_SECRET_ALIAS.to_string()); }

Expand Down
20 changes: 19 additions & 1 deletion vcx/libvcx/src/v3/handlers/issuance/holder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -200,6 +200,18 @@ impl HolderSM {
_ => Err(VcxError::from_msg(VcxErrorKind::NotReady, "Cannot get credential: Credential Issuance is not finished yet"))
}
}

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"))?;
_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<String> {
Expand Down Expand Up @@ -245,6 +257,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 >>> cred_id: {}", cred_id);

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);

Expand Down
4 changes: 4 additions & 0 deletions vcx/libvcx/src/v3/handlers/issuance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,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<u32> {
Ok(self.holder_sm.credential_status())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,31 @@ public static CompletableFuture<String> 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<String> future = (CompletableFuture<String>) 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<String> deleteCredential(
int credentialHandle
) throws VcxException {
ParamGuard.notNull(credentialHandle, "credentialHandle");
logger.debug("deleteCredential() called with: credentialHandle = [" + credentialHandle + "]");
CompletableFuture<String> future = new CompletableFuture<String>();
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) {
Expand Down

0 comments on commit c6c12ee

Please sign in to comment.