diff --git a/Jenkinsfile.cd b/Jenkinsfile.cd index 8005dc36ba..066770b865 100644 --- a/Jenkinsfile.cd +++ b/Jenkinsfile.cd @@ -1766,7 +1766,7 @@ def shell(command) { } def setupRust() { - shell("rustup default 1.39.0") + shell("rustup default 1.40.0") } def androidPublishing() { diff --git a/Jenkinsfile.ci b/Jenkinsfile.ci index 94e7ddd8f9..41fa5a5a94 100644 --- a/Jenkinsfile.ci +++ b/Jenkinsfile.ci @@ -866,7 +866,7 @@ def shell(command) { } def setupRust() { - shell("rustup default 1.39.0") + shell("rustup default 1.40.0") } def setupBrewPackages() { diff --git a/libindy/ci/centos.dockerfile b/libindy/ci/centos.dockerfile index 65f96c1ed6..cab3bbd160 100755 --- a/libindy/ci/centos.dockerfile +++ b/libindy/ci/centos.dockerfile @@ -39,7 +39,7 @@ RUN wget https://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-mav RUN sed -i s/\$releasever/6/g /etc/yum.repos.d/epel-apache-maven.repo RUN yum install -y apache-maven -ENV RUST_ARCHIVE=rust-1.39.0-x86_64-unknown-linux-gnu.tar.gz +ENV RUST_ARCHIVE=rust-1.40.0-x86_64-unknown-linux-gnu.tar.gz ENV RUST_DOWNLOAD_URL=https://static.rust-lang.org/dist/$RUST_ARCHIVE RUN mkdir -p /rust diff --git a/libindy/ci/ubuntu.dockerfile b/libindy/ci/ubuntu.dockerfile index baf90fae05..e3c9663409 100755 --- a/libindy/ci/ubuntu.dockerfile +++ b/libindy/ci/ubuntu.dockerfile @@ -62,7 +62,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.39.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.40.0 ENV PATH /home/indy/.cargo/bin:$PATH RUN cargo install cargo-deb diff --git a/libindy/ci/ubuntu18.dockerfile b/libindy/ci/ubuntu18.dockerfile index 1927d012a2..2a45416f28 100644 --- a/libindy/ci/ubuntu18.dockerfile +++ b/libindy/ci/ubuntu18.dockerfile @@ -43,7 +43,7 @@ RUN apt-get install -y wget RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.39.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.40.0 ENV PATH /home/indy/.cargo/bin:$PATH RUN cargo install cargo-deb diff --git a/vcx/ci/ubuntu.dockerfile b/vcx/ci/ubuntu.dockerfile index 7923522e8c..c93dba410b 100644 --- a/vcx/ci/ubuntu.dockerfile +++ b/vcx/ci/ubuntu.dockerfile @@ -60,7 +60,7 @@ ARG uid=1000 RUN useradd -ms /bin/bash -u $uid vcx USER vcx -ARG RUST_VER="1.39.0" +ARG RUST_VER="1.40.0" RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUST_VER ENV PATH /home/vcx/.cargo/bin:$PATH diff --git a/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh b/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh index ae5f15bb5b..a5ec16022f 100755 --- a/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh +++ b/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh @@ -44,7 +44,7 @@ fi if [[ $RUSTUP_VERSION =~ ^'rustup ' ]]; then rustup update - rustup default 1.39.0 + rustup default 1.40.0 rustup component add rls-preview rust-analysis rust-src echo "Using rustc version $(rustc --version)" rustup target add aarch64-apple-ios armv7-apple-ios armv7s-apple-ios x86_64-apple-ios i386-apple-ios diff --git a/vcx/libvcx/src/api/credential.rs b/vcx/libvcx/src/api/credential.rs index cc8147779e..6dd65cf274 100644 --- a/vcx/libvcx/src/api/credential.rs +++ b/vcx/libvcx/src/api/credential.rs @@ -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) -> 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 diff --git a/vcx/libvcx/src/credential.rs b/vcx/libvcx/src/credential.rs index d7ede3ba7a..7c50faa594 100644 --- a/vcx/libvcx/src/credential.rs +++ b/vcx/libvcx/src/credential.rs @@ -546,6 +546,35 @@ pub fn get_credential(handle: u32) -> VcxResult { }) } +pub fn delete_credential(handle: u32) -> VcxResult { + 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 { 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 f623e870b3..bb7aca47ed 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; @@ -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 { @@ -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); diff --git a/vcx/libvcx/src/v3/handlers/issuance/mod.rs b/vcx/libvcx/src/v3/handlers/issuance/mod.rs index c67807f024..84c5c6bdbd 100644 --- a/vcx/libvcx/src/v3/handlers/issuance/mod.rs +++ b/vcx/libvcx/src/v3/handlers/issuance/mod.rs @@ -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 { Ok(self.holder_sm.credential_status()) } 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) {