Skip to content

Commit

Permalink
Expose get attachment for credential (#175)
Browse files Browse the repository at this point in the history
* Add get attach for credential

Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>

* Add to java / iOS wrappers

Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
  • Loading branch information
mirgee committed Oct 27, 2020
1 parent 7f17f81 commit 565b46d
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 5 deletions.
37 changes: 37 additions & 0 deletions libvcx/src/api/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,43 @@ pub extern fn vcx_credential_get_attributes(command_handle: CommandHandle,
error::SUCCESS.code_num
}

#[no_mangle]
pub extern fn vcx_credential_get_attachment(command_handle: CommandHandle,
credential_handle: u32,
cb: Option<extern fn(xcommand_handle: CommandHandle, err: u32, attachment: *const c_char)>) -> u32 {
info!("vcx_credential_get_attachment >>> credential_handle: {:?}", credential_handle);

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_credential_get_attachment(command_handle: {}, credential_handle: {}) source_id: {})",
command_handle, credential_handle, source_id);

spawn(move || {
match credential::get_attachment(credential_handle) {
Ok(s) => {
trace!("vcx_credential_get_attachment_cb(commmand_handle: {}, rc: {}, attachment: {}) source_id: {}",
command_handle, error::SUCCESS.code_num, s, source_id);
let attach = CStringUtils::string_to_cstring(s);
cb(command_handle, error::SUCCESS.code_num, attach.as_ptr());
}
Err(e) => {
error!("vcx_credential_get_attachment_cb(commmand_handle: {}, rc: {}, attachment: {}) source_id: {}",
command_handle, e, "".to_string(), source_id);
cb(command_handle, e.into(), ptr::null_mut());
}
};

Ok(())
});

error::SUCCESS.code_num
}


/// Create a Credential object based off of a known message id for a given connection.
///
/// #Params
Expand Down
4 changes: 4 additions & 0 deletions libvcx/src/aries/handlers/issuance/holder/holder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ impl Holder {
self.holder_sm.get_attributes()
}

pub fn get_attachment(&self) -> VcxResult<String> {
self.holder_sm.get_attachment()
}

pub fn delete_credential(&self) -> VcxResult<()> {
self.holder_sm.delete_credential()
}
Expand Down
8 changes: 8 additions & 0 deletions libvcx/src/aries/handlers/issuance/holder/state_machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ impl HolderSM {
}
}

pub fn get_attachment(&self) -> VcxResult<String> {
match self.state {
HolderState::Finished(ref state) => state.get_attachment(),
HolderState::OfferReceived(ref state) => state.get_attachment(),
_ => Err(VcxError::from_msg(VcxErrorKind::NotReady, "Cannot get credential attachment: credential offer or credential must be receieved first"))
}
}

pub fn delete_credential(&self) -> VcxResult<()> {
trace!("Holder::delete_credential");

Expand Down
14 changes: 9 additions & 5 deletions libvcx/src/aries/handlers/issuance/holder/states/finished.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ pub struct FinishedHolderState {

impl FinishedHolderState {
pub fn get_attributes(&self) -> VcxResult<String> {
let credential = self.credential.as_ref().ok_or(VcxError::from_msg(VcxErrorKind::InvalidState, "No credential found"))?;
let content = credential.credentials_attach.content()?;
let cred_data: CredentialData = serde_json::from_str(&content)
.map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize {:?}, into CredentialData, err: {:?}", content, err)))?;
let attach = self.get_attachment()?;
let cred_data: CredentialData = serde_json::from_str(&attach)
.map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize {:?}, into CredentialData, err: {:?}", attach, err)))?;

let mut new_map = serde_json::map::Map::new();
match cred_data.values.as_object() {
Expand All @@ -30,7 +29,12 @@ impl FinishedHolderState {
};
Ok(serde_json::Value::Object(new_map).to_string())
}
_ => Err(VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot convert {:?} into object", content)))
_ => Err(VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot convert {:?} into object", attach)))
}
}

pub fn get_attachment(&self) -> VcxResult<String> {
let credential = self.credential.as_ref().ok_or(VcxError::from_msg(VcxErrorKind::InvalidState, "No credential found"))?;
credential.credentials_attach.content()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@ impl OfferReceivedState {
});
Ok(serde_json::Value::Object(new_map).to_string())
}

pub fn get_attachment(&self) -> VcxResult<String> {
self.offer.offers_attach.content()
}
}
6 changes: 6 additions & 0 deletions libvcx/src/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ pub fn get_attributes(handle: u32) -> VcxResult<String> {
})
}

pub fn get_attachment(handle: u32) -> VcxResult<String> {
HANDLE_MAP.get(handle, |credential| {
credential.get_attachment()
})
}

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);
Expand Down
17 changes: 17 additions & 0 deletions wrappers/ios/vcx/ConnectMeVcx.m
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,23 @@ - (void)credentialGetAttributes:(VcxHandle)credentialHandle
}
}

- (void)credentialGetAttachment:(VcxHandle)credentialHandle
completion:(void (^)(NSError *error, NSString *attach))completion{
vcx_error_t ret;
vcx_command_handle_t handle = [[VcxCallbacks sharedInstance] createCommandHandleFor:completion];

ret = vcx_credential_get_attachment(handle, credentialHandle, VcxWrapperCommonStringCallback);

if( ret != 0 )
{
[[VcxCallbacks sharedInstance] deleteCommandHandleFor: handle];

dispatch_async(dispatch_get_main_queue(), ^{
completion([NSError errorFromVcxError: ret],nil);
});
}
}

- (void)generateProof:(NSString *)proofRequestId
requestedAttrs:(NSString *)requestedAttrs
requestedPredicates:(NSString *)requestedPredicates
Expand Down
2 changes: 2 additions & 0 deletions wrappers/ios/vcx/include/libvcx.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ vcx_error_t vcx_credential_get_offers(vcx_command_handle_t command_handle, vcx_c
/** Get attributes for specified credential */
vcx_error_t vcx_credential_get_attributes(vcx_command_handle_t handle, vcx_credential_handle_t credential_handle, void (*cb)(vcx_command_handle_t command_handle, vcx_error_t err, const char *attributes));

vcx_error_t vcx_credential_get_attachment(vcx_command_handle_t handle, vcx_credential_handle_t credential_handle, void (*cb)(vcx_command_handle_t command_handle, vcx_error_t err, const char *attachment));

/** Updates the state of the credential from the agency. */
vcx_error_t vcx_credential_update_state(vcx_command_handle_t command_handle, vcx_credential_handle_t credential_handle, void (*cb)(vcx_command_handle_t xcommand_handle, vcx_error_t err, vcx_state_t state));

Expand Down
2 changes: 2 additions & 0 deletions wrappers/java/src/main/java/com/evernym/sdk/vcx/LibVcx.java
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,8 @@ public interface API extends Library {
/** Retrieves attributes present in the credential or credential offer, depending on credential state */
public int vcx_credential_get_attributes(int command_handle, int credential_handle, Callback cb);

public int vcx_credential_get_attachment(int command_handle, int credential_handle, Callback cb);

/** Populates status with the current State of this credential. */
public int vcx_credential_serialize(int command_handle, int credential_handle, Callback cb);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,30 @@ public static CompletableFuture<String> credentialGetAttributes(
return future;
}

private static Callback vcxCredentialGetAttachmentCB = new Callback() {
@SuppressWarnings({"unused", "unchecked"})
public void callback(int command_handle, int err, String attachment) {
logger.debug("vcxCredentialGetAttachmentCB() called with: command_handle = [" + command_handle + "], err = [" + err + "], attachment = [" + attachment + "]");
CompletableFuture<String> future = (CompletableFuture<String>) removeFuture(command_handle);
if (!checkCallback(future, err)) return;
future.complete(attachment);
}
};

public static CompletableFuture<String> credentialGetAttachment(
int credentialHandle
) throws VcxException {
ParamGuard.notNull(credentialHandle, "credentialHandle");
logger.debug("getAttachment() called with: credentialHandle = [" + credentialHandle + "]");
CompletableFuture<String> future = new CompletableFuture<String>();
int commandHandle = addFuture(future);

int result = LibVcx.api.vcx_credential_get_attachment(commandHandle, credentialHandle, vcxCredentialGetAttachmentCB);
checkResult(result);

return future;
}

public static int credentialRelease(int credentialHandle) throws VcxException {
ParamGuard.notNull(credentialHandle, "credentialHandle");
logger.debug("credentialRelease() called with: credentialHandle = [" + credentialHandle + "]");
Expand Down
27 changes: 27 additions & 0 deletions wrappers/node/src/api/credential.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,33 @@ export class Credential extends VCXBaseWithState<ICredentialStructData> {
}
}

public async getAttachment (connection: Connection): Promise<string> {
try {
const attach = await createFFICallbackPromise<string>(
(resolve, reject, cb) => {
const rc = rustAPI().vcx_credential_get_attachment(0, this.handle, cb)
if (rc) {
reject(rc)
}
},
(resolve, reject) => Callback(
'void',
['uint32', 'uint32', 'string'],
(handle: number, err: number, messages: string) => {
if (err) {
reject(err)
return
}
resolve(messages)
})
)
return attach
} catch (err) {
throw new VCXInternalError(err)
}
}


get credOffer (): string {
return this._credOffer
}
Expand Down
3 changes: 3 additions & 0 deletions wrappers/node/src/rustlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ export interface IFFIEntryPoint {
vcx_credential_get_state: (commandId: number, handle: number, cb: any) => number,
vcx_credential_get_offers: (commandId: number, connectionHandle: number, cb: any) => number,
vcx_credential_get_attributes: (commandId: number, connectionHandle: number, cb: any) => number,
vcx_credential_get_attachment: (commandId: number, connectionHandle: number, cb: any) => number,
vcx_credential_get_payment_info: (commandId: number, handle: number, cb: any) => number,
vcx_credential_get_payment_txn: (commandId: number, handle: number, cb: any) => number,

Expand Down Expand Up @@ -428,6 +429,8 @@ export const FFIConfiguration: { [ Key in keyof IFFIEntryPoint ]: any } = {
vcx_credential_get_offers: [FFI_ERROR_CODE, [FFI_COMMAND_HANDLE, FFI_CONNECTION_HANDLE, FFI_CALLBACK_PTR]],
vcx_credential_get_attributes: [FFI_ERROR_CODE, [FFI_COMMAND_HANDLE, FFI_CONNECTION_HANDLE,
FFI_CALLBACK_PTR]],
vcx_credential_get_attachment: [FFI_ERROR_CODE, [FFI_COMMAND_HANDLE, FFI_CONNECTION_HANDLE,
FFI_CALLBACK_PTR]],
vcx_credential_get_payment_info: [FFI_ERROR_CODE, [FFI_COMMAND_HANDLE, FFI_CREDENTIAL_HANDLE,FFI_CALLBACK_PTR]],
vcx_credential_get_payment_txn: [FFI_ERROR_CODE, [FFI_COMMAND_HANDLE, FFI_CREDENTIAL_HANDLE,FFI_CALLBACK_PTR]],

Expand Down
17 changes: 17 additions & 0 deletions wrappers/node/test/suite1/ariesvcx-credential.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,23 @@ describe('Credential:', () => {
})
})

describe('getAttachment:', () => {
it('success', async () => {
const connection = await createConnectionInviterRequested()
const offers = await Credential.getOffers(connection)
assert.ok(offers)
assert.ok(offers.length)
const offer = offers[0]
const credential = await credentialCreateWithOffer({
connection,
offer: JSON.stringify(offer),
sourceId: 'credentialGetAttributesTestSourceId'
})
const attach = JSON.parse(await credential.getAttachment(connection))
assert.deepEqual(attach.schema_id, 'V4SGRU86Z58d6TV7PBUe6f:2:FaberVcx:83.23.62')
})
})

describe('getPaymentInfo:', () => {
it.skip('success', async () => {
const credential = await credentialCreateWithOffer()
Expand Down

0 comments on commit 565b46d

Please sign in to comment.