Skip to content

Commit 565b46d

Browse files
authored
Expose get attachment for credential (#175)
* 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>
1 parent 7f17f81 commit 565b46d

File tree

13 files changed

+160
-5
lines changed

13 files changed

+160
-5
lines changed

libvcx/src/api/credential.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,43 @@ pub extern fn vcx_credential_get_attributes(command_handle: CommandHandle,
272272
error::SUCCESS.code_num
273273
}
274274

275+
#[no_mangle]
276+
pub extern fn vcx_credential_get_attachment(command_handle: CommandHandle,
277+
credential_handle: u32,
278+
cb: Option<extern fn(xcommand_handle: CommandHandle, err: u32, attachment: *const c_char)>) -> u32 {
279+
info!("vcx_credential_get_attachment >>> credential_handle: {:?}", credential_handle);
280+
281+
check_useful_c_callback!(cb, VcxErrorKind::InvalidOption);
282+
if !credential::is_valid_handle(credential_handle) {
283+
return VcxError::from(VcxErrorKind::InvalidCredentialHandle).into();
284+
}
285+
286+
let source_id = credential::get_source_id(credential_handle).unwrap_or_default();
287+
trace!("vcx_credential_get_attachment(command_handle: {}, credential_handle: {}) source_id: {})",
288+
command_handle, credential_handle, source_id);
289+
290+
spawn(move || {
291+
match credential::get_attachment(credential_handle) {
292+
Ok(s) => {
293+
trace!("vcx_credential_get_attachment_cb(commmand_handle: {}, rc: {}, attachment: {}) source_id: {}",
294+
command_handle, error::SUCCESS.code_num, s, source_id);
295+
let attach = CStringUtils::string_to_cstring(s);
296+
cb(command_handle, error::SUCCESS.code_num, attach.as_ptr());
297+
}
298+
Err(e) => {
299+
error!("vcx_credential_get_attachment_cb(commmand_handle: {}, rc: {}, attachment: {}) source_id: {}",
300+
command_handle, e, "".to_string(), source_id);
301+
cb(command_handle, e.into(), ptr::null_mut());
302+
}
303+
};
304+
305+
Ok(())
306+
});
307+
308+
error::SUCCESS.code_num
309+
}
310+
311+
275312
/// Create a Credential object based off of a known message id for a given connection.
276313
///
277314
/// #Params

libvcx/src/aries/handlers/issuance/holder/holder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ impl Holder {
5555
self.holder_sm.get_attributes()
5656
}
5757

58+
pub fn get_attachment(&self) -> VcxResult<String> {
59+
self.holder_sm.get_attachment()
60+
}
61+
5862
pub fn delete_credential(&self) -> VcxResult<()> {
5963
self.holder_sm.delete_credential()
6064
}

libvcx/src/aries/handlers/issuance/holder/state_machine.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ impl HolderSM {
219219
}
220220
}
221221

222+
pub fn get_attachment(&self) -> VcxResult<String> {
223+
match self.state {
224+
HolderState::Finished(ref state) => state.get_attachment(),
225+
HolderState::OfferReceived(ref state) => state.get_attachment(),
226+
_ => Err(VcxError::from_msg(VcxErrorKind::NotReady, "Cannot get credential attachment: credential offer or credential must be receieved first"))
227+
}
228+
}
229+
222230
pub fn delete_credential(&self) -> VcxResult<()> {
223231
trace!("Holder::delete_credential");
224232

libvcx/src/aries/handlers/issuance/holder/states/finished.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ pub struct FinishedHolderState {
1313

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

2120
let mut new_map = serde_json::map::Map::new();
2221
match cred_data.values.as_object() {
@@ -30,7 +29,12 @@ impl FinishedHolderState {
3029
};
3130
Ok(serde_json::Value::Object(new_map).to_string())
3231
}
33-
_ => Err(VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot convert {:?} into object", content)))
32+
_ => Err(VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot convert {:?} into object", attach)))
3433
}
3534
}
35+
36+
pub fn get_attachment(&self) -> VcxResult<String> {
37+
let credential = self.credential.as_ref().ok_or(VcxError::from_msg(VcxErrorKind::InvalidState, "No credential found"))?;
38+
credential.credentials_attach.content()
39+
}
3640
}

libvcx/src/aries/handlers/issuance/holder/states/offer_received.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,8 @@ impl OfferReceivedState {
4848
});
4949
Ok(serde_json::Value::Object(new_map).to_string())
5050
}
51+
52+
pub fn get_attachment(&self) -> VcxResult<String> {
53+
self.offer.offers_attach.content()
54+
}
5155
}

libvcx/src/credential.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ pub fn get_attributes(handle: u32) -> VcxResult<String> {
123123
})
124124
}
125125

126+
pub fn get_attachment(handle: u32) -> VcxResult<String> {
127+
HANDLE_MAP.get(handle, |credential| {
128+
credential.get_attachment()
129+
})
130+
}
131+
126132
pub fn delete_credential(handle: u32) -> VcxResult<u32> {
127133
let source_id = get_source_id(handle).unwrap_or_default();
128134
trace!("Credential::delete_credential >>> credential_handle: {}, source_id: {}", handle, source_id);

wrappers/ios/vcx/ConnectMeVcx.m

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,23 @@ - (void)credentialGetAttributes:(VcxHandle)credentialHandle
813813
}
814814
}
815815

816+
- (void)credentialGetAttachment:(VcxHandle)credentialHandle
817+
completion:(void (^)(NSError *error, NSString *attach))completion{
818+
vcx_error_t ret;
819+
vcx_command_handle_t handle = [[VcxCallbacks sharedInstance] createCommandHandleFor:completion];
820+
821+
ret = vcx_credential_get_attachment(handle, credentialHandle, VcxWrapperCommonStringCallback);
822+
823+
if( ret != 0 )
824+
{
825+
[[VcxCallbacks sharedInstance] deleteCommandHandleFor: handle];
826+
827+
dispatch_async(dispatch_get_main_queue(), ^{
828+
completion([NSError errorFromVcxError: ret],nil);
829+
});
830+
}
831+
}
832+
816833
- (void)generateProof:(NSString *)proofRequestId
817834
requestedAttrs:(NSString *)requestedAttrs
818835
requestedPredicates:(NSString *)requestedPredicates

wrappers/ios/vcx/include/libvcx.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,8 @@ vcx_error_t vcx_credential_get_offers(vcx_command_handle_t command_handle, vcx_c
351351
/** Get attributes for specified credential */
352352
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));
353353

354+
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));
355+
354356
/** Updates the state of the credential from the agency. */
355357
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));
356358

wrappers/java/src/main/java/com/evernym/sdk/vcx/LibVcx.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,8 @@ public interface API extends Library {
531531
/** Retrieves attributes present in the credential or credential offer, depending on credential state */
532532
public int vcx_credential_get_attributes(int command_handle, int credential_handle, Callback cb);
533533

534+
public int vcx_credential_get_attachment(int command_handle, int credential_handle, Callback cb);
535+
534536
/** Populates status with the current State of this credential. */
535537
public int vcx_credential_serialize(int command_handle, int credential_handle, Callback cb);
536538

wrappers/java/src/main/java/com/evernym/sdk/vcx/credential/CredentialApi.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,30 @@ public static CompletableFuture<String> credentialGetAttributes(
313313
return future;
314314
}
315315

316+
private static Callback vcxCredentialGetAttachmentCB = new Callback() {
317+
@SuppressWarnings({"unused", "unchecked"})
318+
public void callback(int command_handle, int err, String attachment) {
319+
logger.debug("vcxCredentialGetAttachmentCB() called with: command_handle = [" + command_handle + "], err = [" + err + "], attachment = [" + attachment + "]");
320+
CompletableFuture<String> future = (CompletableFuture<String>) removeFuture(command_handle);
321+
if (!checkCallback(future, err)) return;
322+
future.complete(attachment);
323+
}
324+
};
325+
326+
public static CompletableFuture<String> credentialGetAttachment(
327+
int credentialHandle
328+
) throws VcxException {
329+
ParamGuard.notNull(credentialHandle, "credentialHandle");
330+
logger.debug("getAttachment() called with: credentialHandle = [" + credentialHandle + "]");
331+
CompletableFuture<String> future = new CompletableFuture<String>();
332+
int commandHandle = addFuture(future);
333+
334+
int result = LibVcx.api.vcx_credential_get_attachment(commandHandle, credentialHandle, vcxCredentialGetAttachmentCB);
335+
checkResult(result);
336+
337+
return future;
338+
}
339+
316340
public static int credentialRelease(int credentialHandle) throws VcxException {
317341
ParamGuard.notNull(credentialHandle, "credentialHandle");
318342
logger.debug("credentialRelease() called with: credentialHandle = [" + credentialHandle + "]");

wrappers/node/src/api/credential.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,33 @@ export class Credential extends VCXBaseWithState<ICredentialStructData> {
382382
}
383383
}
384384

385+
public async getAttachment (connection: Connection): Promise<string> {
386+
try {
387+
const attach = await createFFICallbackPromise<string>(
388+
(resolve, reject, cb) => {
389+
const rc = rustAPI().vcx_credential_get_attachment(0, this.handle, cb)
390+
if (rc) {
391+
reject(rc)
392+
}
393+
},
394+
(resolve, reject) => Callback(
395+
'void',
396+
['uint32', 'uint32', 'string'],
397+
(handle: number, err: number, messages: string) => {
398+
if (err) {
399+
reject(err)
400+
return
401+
}
402+
resolve(messages)
403+
})
404+
)
405+
return attach
406+
} catch (err) {
407+
throw new VCXInternalError(err)
408+
}
409+
}
410+
411+
385412
get credOffer (): string {
386413
return this._credOffer
387414
}

wrappers/node/src/rustlib.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ export interface IFFIEntryPoint {
208208
vcx_credential_get_state: (commandId: number, handle: number, cb: any) => number,
209209
vcx_credential_get_offers: (commandId: number, connectionHandle: number, cb: any) => number,
210210
vcx_credential_get_attributes: (commandId: number, connectionHandle: number, cb: any) => number,
211+
vcx_credential_get_attachment: (commandId: number, connectionHandle: number, cb: any) => number,
211212
vcx_credential_get_payment_info: (commandId: number, handle: number, cb: any) => number,
212213
vcx_credential_get_payment_txn: (commandId: number, handle: number, cb: any) => number,
213214

@@ -428,6 +429,8 @@ export const FFIConfiguration: { [ Key in keyof IFFIEntryPoint ]: any } = {
428429
vcx_credential_get_offers: [FFI_ERROR_CODE, [FFI_COMMAND_HANDLE, FFI_CONNECTION_HANDLE, FFI_CALLBACK_PTR]],
429430
vcx_credential_get_attributes: [FFI_ERROR_CODE, [FFI_COMMAND_HANDLE, FFI_CONNECTION_HANDLE,
430431
FFI_CALLBACK_PTR]],
432+
vcx_credential_get_attachment: [FFI_ERROR_CODE, [FFI_COMMAND_HANDLE, FFI_CONNECTION_HANDLE,
433+
FFI_CALLBACK_PTR]],
431434
vcx_credential_get_payment_info: [FFI_ERROR_CODE, [FFI_COMMAND_HANDLE, FFI_CREDENTIAL_HANDLE,FFI_CALLBACK_PTR]],
432435
vcx_credential_get_payment_txn: [FFI_ERROR_CODE, [FFI_COMMAND_HANDLE, FFI_CREDENTIAL_HANDLE,FFI_CALLBACK_PTR]],
433436

wrappers/node/test/suite1/ariesvcx-credential.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,23 @@ describe('Credential:', () => {
176176
})
177177
})
178178

179+
describe('getAttachment:', () => {
180+
it('success', async () => {
181+
const connection = await createConnectionInviterRequested()
182+
const offers = await Credential.getOffers(connection)
183+
assert.ok(offers)
184+
assert.ok(offers.length)
185+
const offer = offers[0]
186+
const credential = await credentialCreateWithOffer({
187+
connection,
188+
offer: JSON.stringify(offer),
189+
sourceId: 'credentialGetAttributesTestSourceId'
190+
})
191+
const attach = JSON.parse(await credential.getAttachment(connection))
192+
assert.deepEqual(attach.schema_id, 'V4SGRU86Z58d6TV7PBUe6f:2:FaberVcx:83.23.62')
193+
})
194+
})
195+
179196
describe('getPaymentInfo:', () => {
180197
it.skip('success', async () => {
181198
const credential = await credentialCreateWithOffer()

0 commit comments

Comments
 (0)