diff --git a/wrappers/javascript/aries-askar-nodejs/src/NodeJSAriesAskar.ts b/wrappers/javascript/aries-askar-nodejs/src/NodeJSAriesAskar.ts index 1ab841f4..b178c7c6 100644 --- a/wrappers/javascript/aries-askar-nodejs/src/NodeJSAriesAskar.ts +++ b/wrappers/javascript/aries-askar-nodejs/src/NodeJSAriesAskar.ts @@ -82,6 +82,7 @@ import type { } from '@hyperledger/aries-askar-shared' import { + handleInvalidNullResponse, AriesAskarError, ScanHandle, EntryListHandle, @@ -119,6 +120,19 @@ import { } from './ffi' import { nativeAriesAskar } from './library' +function handleNullableReturnPointer(returnValue: Buffer): Return | null { + if (returnValue.address() === 0) return null + return returnValue.deref() as Return +} + +function handleReturnPointer(returnValue: Buffer): Return { + if (returnValue.address() === 0) { + throw AriesAskarError.customError({ message: 'Unexpected null pointer' }) + } + + return returnValue.deref() as Return +} + export class NodeJSAriesAskar implements AriesAskar { private promisify = async (method: (nativeCallbackPtr: Buffer, id: number) => void): Promise => { return new Promise((resolve, reject) => { @@ -141,7 +155,7 @@ export class NodeJSAriesAskar implements AriesAskar { private promisifyWithResponse = async ( method: (nativeCallbackWithResponsePtr: Buffer, id: number) => void, responseFfiType = FFI_STRING - ): Promise => { + ): Promise => { return new Promise((resolve, reject) => { const cb: NativeCallbackWithResponse = (id, errorCode, response) => { deallocateCallbackBuffer(id) @@ -162,12 +176,7 @@ export class NodeJSAriesAskar implements AriesAskar { } else if (typeof response === 'number') { resolve(response as unknown as Return) } else if (response instanceof Buffer) { - if (response.address() === 0) - return reject( - AriesAskarError.customError({ - message: 'Received null pointer. The native library could not find the value.', - }) - ) + if (response.address() === 0) return resolve(null) resolve(response as unknown as Return) } @@ -187,7 +196,7 @@ export class NodeJSAriesAskar implements AriesAskar { const error = allocateStringBuffer() nativeAriesAskar.askar_get_current_error(error) handleError() - return error.deref() as string + return handleReturnPointer(error) } public clearCustomLogger(): void { @@ -224,7 +233,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_entry_list_count(entryListHandle, ret) handleError() - return ret.deref() as number + return handleReturnPointer(ret) } public entryListFree(options: EntryListFreeOptions): void { @@ -241,7 +250,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_entry_list_get_category(entryListHandle, index, ret) handleError() - return ret.deref() as string + return handleReturnPointer(ret) } public entryListGetName(options: EntryListGetNameOptions): string { @@ -251,17 +260,17 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_entry_list_get_name(entryListHandle, index, ret) handleError() - return ret.deref() as string + return handleReturnPointer(ret) } - public entryListGetTags(options: EntryListGetTagsOptions): string { + public entryListGetTags(options: EntryListGetTagsOptions): string | null { const { entryListHandle, index } = serializeArguments(options) const ret = allocateStringBuffer() nativeAriesAskar.askar_entry_list_get_tags(entryListHandle, index, ret) handleError() - return ret.deref() as string + return handleNullableReturnPointer(ret) } public entryListGetValue(options: EntryListGetValueOptions): Uint8Array { @@ -272,7 +281,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_entry_list_get_value(entryListHandle, index, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as ByteBufferType)) + const byteBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(byteBuffer)) } public keyAeadDecrypt(options: KeyAeadDecryptOptions): Uint8Array { @@ -282,7 +292,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_aead_decrypt(localKeyHandle, ciphertext, nonce, tag, aad, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as ByteBufferType)) + const byteBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(byteBuffer)) } public keyAeadEncrypt(options: KeyAeadEncryptOptions): EncryptedBuffer { @@ -292,7 +303,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_aead_encrypt(localKeyHandle, message, nonce, aad, ret) handleError() - return encryptedBufferStructToClass(ret.deref() as EncryptedBufferType) + const encryptedBuffer = handleReturnPointer(ret) + return encryptedBufferStructToClass(encryptedBuffer) } public keyAeadGetPadding(options: KeyAeadGetPaddingOptions): number { @@ -302,7 +314,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_aead_get_padding(localKeyHandle, msgLen, ret) handleError() - return ret.deref() as number + return handleReturnPointer(ret) } public keyAeadGetParams(options: KeyAeadGetParamsOptions): AeadParams { @@ -312,7 +324,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_aead_get_params(localKeyHandle, ret) handleError() - return new AeadParams(ret.deref() as AeadParamsOptions) + return new AeadParams(handleReturnPointer(ret)) } public keyAeadRandomNonce(options: KeyAeadRandomNonceOptions): Uint8Array { @@ -322,7 +334,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_aead_random_nonce(localKeyHandle, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as SecretBufferType)) + const secretBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(secretBuffer)) } public keyConvert(options: KeyConvertOptions): LocalKeyHandle { @@ -332,7 +345,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_convert(localKeyHandle, algorithm, ret) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyCryptoBox(options: KeyCryptoBoxOptions): Uint8Array { @@ -342,7 +356,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_crypto_box(recipientKey, senderKey, message, nonce, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as SecretBufferType)) + const secretBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(secretBuffer)) } public keyCryptoBoxOpen(options: KeyCryptoBoxOpenOptions): Uint8Array { @@ -352,7 +367,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_crypto_box_open(recipientKey, senderKey, message, nonce, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as SecretBufferType)) + const secretBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(secretBuffer)) } public keyCryptoBoxRandomNonce(): Uint8Array { @@ -361,7 +377,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_crypto_box_random_nonce(ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as SecretBufferType)) + const secretBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(secretBuffer)) } public keyCryptoBoxSeal(options: KeyCryptoBoxSealOptions): Uint8Array { @@ -371,7 +388,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_crypto_box_seal(localKeyHandle, message, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as SecretBufferType)) + const secretBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(secretBuffer)) } public keyCryptoBoxSealOpen(options: KeyCryptoBoxSealOpenOptions): Uint8Array { @@ -381,7 +399,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_crypto_box_seal_open(localKeyHandle, ciphertext, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as SecretBufferType)) + const secretBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(secretBuffer)) } public keyDeriveEcdh1pu(options: KeyDeriveEcdh1puOptions): LocalKeyHandle { @@ -404,7 +423,8 @@ export class NodeJSAriesAskar implements AriesAskar { ) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyDeriveEcdhEs(options: KeyDeriveEcdhEsOptions): LocalKeyHandle { @@ -414,7 +434,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_derive_ecdh_es(algorithm, ephemeralKey, recipientKey, algId, apu, apv, receive, ret) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyEntryListCount(options: KeyEntryListCountOptions): number { @@ -424,7 +445,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_entry_list_count(keyEntryListHandle, ret) handleError() - return ret.deref() as number + return handleReturnPointer(ret) } public keyEntryListFree(options: KeyEntryListFreeOptions): void { @@ -441,17 +462,17 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_entry_list_get_algorithm(keyEntryListHandle, index, ret) handleError() - return ret.deref() as string + return handleReturnPointer(ret) } - public keyEntryListGetMetadata(options: KeyEntryListGetMetadataOptions): string { + public keyEntryListGetMetadata(options: KeyEntryListGetMetadataOptions): string | null { const { keyEntryListHandle, index } = serializeArguments(options) const ret = allocateStringBuffer() nativeAriesAskar.askar_key_entry_list_get_metadata(keyEntryListHandle, index, ret) handleError() - return ret.deref() as string + return handleNullableReturnPointer(ret) } public keyEntryListGetName(options: KeyEntryListGetNameOptions): string { @@ -461,16 +482,16 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_entry_list_get_name(keyEntryListHandle, index, ret) handleError() - return ret.deref() as string + return handleReturnPointer(ret) } - public keyEntryListGetTags(options: KeyEntryListGetTagsOptions): string { + public keyEntryListGetTags(options: KeyEntryListGetTagsOptions): string | null { const { keyEntryListHandle, index } = serializeArguments(options) const ret = allocateStringBuffer() nativeAriesAskar.askar_key_entry_list_get_tags(keyEntryListHandle, index, ret) - return ret.deref() as string + return handleNullableReturnPointer(ret) } public keyEntryListLoadLocal(options: KeyEntryListLoadLocalOptions): LocalKeyHandle { @@ -480,7 +501,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_entry_list_load_local(keyEntryListHandle, index, ret) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyFree(options: KeyFreeOptions): void { @@ -497,7 +519,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_from_jwk(jwk, ret) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyFromKeyExchange(options: KeyFromKeyExchangeOptions): LocalKeyHandle { @@ -507,7 +530,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_from_key_exchange(algorithm, skHandle, pkHandle, ret) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyFromPublicBytes(options: KeyFromPublicBytesOptions): LocalKeyHandle { @@ -517,7 +541,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_from_public_bytes(algorithm, publicKey, ret) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyFromSecretBytes(options: KeyFromSecretBytesOptions): LocalKeyHandle { @@ -527,7 +552,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_from_secret_bytes(algorithm, secretKey, ret) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyFromSeed(options: KeyFromSeedOptions): LocalKeyHandle { @@ -537,7 +563,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_from_seed(algorithm, seed, method, ret) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyGenerate(options: KeyGenerateOptions): LocalKeyHandle { @@ -547,7 +574,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_generate(algorithm, ephemeral, ret) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyGetAlgorithm(options: KeyGetAlgorithmOptions): string { @@ -557,7 +585,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_get_algorithm(localKeyHandle, ret) handleError() - return ret.deref() as string + return handleReturnPointer(ret) } public keyGetEphemeral(options: KeyGetEphemeralOptions): number { @@ -567,7 +595,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_get_ephemeral(localKeyHandle, ret) handleError() - return ret.deref() as number + return handleReturnPointer(ret) } public keyGetJwkPublic(options: KeyGetJwkPublicOptions): string { @@ -577,7 +605,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_get_jwk_public(localKeyHandle, algorithm, ret) handleError() - return ret.deref() as string + return handleReturnPointer(ret) } public keyGetJwkSecret(options: KeyGetJwkSecretOptions): Uint8Array { @@ -587,7 +615,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_get_jwk_secret(localKeyHandle, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as SecretBufferType)) + const secretBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(secretBuffer)) } public keyGetJwkThumbprint(options: KeyGetJwkThumbprintOptions): string { @@ -597,7 +626,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_get_jwk_thumbprint(localKeyHandle, algorithm, ret) handleError() - return ret.deref() as string + return handleReturnPointer(ret) } public keyGetPublicBytes(options: KeyGetPublicBytesOptions): Uint8Array { @@ -607,7 +636,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_get_public_bytes(localKeyHandle, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as SecretBufferType)) + const secretBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(secretBuffer)) } public keyGetSecretBytes(options: KeyGetSecretBytesOptions): Uint8Array { @@ -617,7 +647,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_get_secret_bytes(localKeyHandle, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as SecretBufferType)) + const secretBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(secretBuffer)) } public keySignMessage(options: KeySignMessageOptions): Uint8Array { @@ -627,7 +658,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_sign_message(localKeyHandle, message, sigType, ret) handleError() - return new Uint8Array(secretBufferToBuffer(ret.deref() as SecretBufferType)) + const secretBuffer = handleReturnPointer(ret) + return new Uint8Array(secretBufferToBuffer(secretBuffer)) } public keyUnwrapKey(options: KeyUnwrapKeyOptions): LocalKeyHandle { @@ -637,7 +669,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_unwrap_key(localKeyHandle, algorithm, ciphertext, nonce, tag, ret) handleError() - return new LocalKeyHandle(ret.deref() as Uint8Array) + const handle = handleReturnPointer(ret) + return new LocalKeyHandle(handle) } public keyVerifySignature(options: KeyVerifySignatureOptions): boolean { @@ -647,7 +680,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_verify_signature(localKeyHandle, message, signature, sigType, ret) handleError() - return Boolean(ret.deref()) + return Boolean(handleReturnPointer(ret)) } public keyWrapKey(options: KeyWrapKeyOptions): EncryptedBuffer { @@ -657,7 +690,8 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_key_wrap_key(localKeyHandle, other, nonce, ret) handleError() - return encryptedBufferStructToClass(ret.deref() as EncryptedBufferType) + const encryptedBuffer = handleReturnPointer(ret) + return encryptedBufferStructToClass(encryptedBuffer) } public scanFree(options: ScanFreeOptions): void { @@ -667,7 +701,7 @@ export class NodeJSAriesAskar implements AriesAskar { handleError() } - public async scanNext(options: ScanNextOptions): Promise { + public async scanNext(options: ScanNextOptions): Promise { const { scanHandle } = serializeArguments(options) const handle = await this.promisifyWithResponse( @@ -675,7 +709,7 @@ export class NodeJSAriesAskar implements AriesAskar { FFI_ENTRY_LIST_HANDLE ) - return new EntryListHandle(handle) + return EntryListHandle.fromHandle(handle) } public async scanStart(options: ScanStartOptions): Promise { @@ -695,7 +729,7 @@ export class NodeJSAriesAskar implements AriesAskar { FFI_SCAN_HANDLE ) - return new ScanHandle(handle) + return ScanHandle.fromHandle(handle) } public async sessionClose(options: SessionCloseOptions): Promise { @@ -706,23 +740,25 @@ export class NodeJSAriesAskar implements AriesAskar { public async sessionCount(options: SessionCountOptions): Promise { const { sessionHandle, tagFilter, category } = serializeArguments(options) - return this.promisifyWithResponse( + const response = await this.promisifyWithResponse( (cb, cbId) => nativeAriesAskar.askar_session_count(sessionHandle, category, tagFilter, cb, cbId), FFI_INT64 ) + + return handleInvalidNullResponse(response) } - public async sessionFetch(options: SessionFetchOptions): Promise { + public async sessionFetch(options: SessionFetchOptions): Promise { const { name, category, sessionHandle, forUpdate } = serializeArguments(options) const handle = await this.promisifyWithResponse( (cb, cbId) => nativeAriesAskar.askar_session_fetch(sessionHandle, category, name, forUpdate, cb, cbId), FFI_ENTRY_LIST_HANDLE ) - return new EntryListHandle(handle) + return EntryListHandle.fromHandle(handle) } - public async sessionFetchAll(options: SessionFetchAllOptions): Promise { + public async sessionFetchAll(options: SessionFetchAllOptions): Promise { const { forUpdate, sessionHandle, tagFilter, limit, category } = serializeArguments(options) const handle = await this.promisifyWithResponse( @@ -731,10 +767,10 @@ export class NodeJSAriesAskar implements AriesAskar { FFI_ENTRY_LIST_HANDLE ) - return new EntryListHandle(handle) + return EntryListHandle.fromHandle(handle) } - public async sessionFetchAllKeys(options: SessionFetchAllKeysOptions): Promise { + public async sessionFetchAllKeys(options: SessionFetchAllKeysOptions): Promise { const { forUpdate, limit, tagFilter, sessionHandle, algorithm, thumbprint } = serializeArguments(options) const handle = await this.promisifyWithResponse( @@ -752,10 +788,10 @@ export class NodeJSAriesAskar implements AriesAskar { FFI_KEY_ENTRY_LIST_HANDLE ) - return new KeyEntryListHandle(handle) + return KeyEntryListHandle.fromHandle(handle) } - public async sessionFetchKey(options: SessionFetchKeyOptions): Promise { + public async sessionFetchKey(options: SessionFetchKeyOptions): Promise { const { forUpdate, sessionHandle, name } = serializeArguments(options) const handle = await this.promisifyWithResponse( @@ -763,7 +799,7 @@ export class NodeJSAriesAskar implements AriesAskar { FFI_KEY_ENTRY_LIST_HANDLE ) - return new KeyEntryListHandle(handle) + return KeyEntryListHandle.fromHandle(handle) } public async sessionInsertKey(options: SessionInsertKeyOptions): Promise { @@ -785,11 +821,12 @@ export class NodeJSAriesAskar implements AriesAskar { public async sessionRemoveAll(options: SessionRemoveAllOptions): Promise { const { sessionHandle, tagFilter, category } = serializeArguments(options) - - return this.promisifyWithResponse( + const response = await this.promisifyWithResponse( (cb, cbId) => nativeAriesAskar.askar_session_remove_all(sessionHandle, category, tagFilter, cb, cbId), FFI_INT64 ) + + return handleInvalidNullResponse(response) } public async sessionRemoveKey(options: SessionRemoveKeyOptions): Promise { @@ -805,7 +842,7 @@ export class NodeJSAriesAskar implements AriesAskar { nativeAriesAskar.askar_session_start(storeHandle, profile, asTransaction, cb, cbId) }, FFI_SESSION_HANDLE) - return new SessionHandle(handle) + return SessionHandle.fromHandle(handle) } public async sessionUpdate(options: SessionUpdateOptions): Promise { @@ -840,13 +877,14 @@ export class NodeJSAriesAskar implements AriesAskar { return this.promisify((cb, cbId) => nativeAriesAskar.askar_store_close(storeHandle, cb, cbId)) } - public storeCreateProfile(options: StoreCreateProfileOptions): Promise { + public async storeCreateProfile(options: StoreCreateProfileOptions): Promise { const { storeHandle, profile } = serializeArguments(options) - - return this.promisifyWithResponse( + const response = await this.promisifyWithResponse( (cb, cbId) => nativeAriesAskar.askar_store_create_profile(storeHandle, profile, cb, cbId), FFI_STRING ) + + return handleInvalidNullResponse(response) } public storeGenerateRawKey(options: StoreGenerateRawKeyOptions): string { @@ -861,10 +899,11 @@ export class NodeJSAriesAskar implements AriesAskar { public async storeGetProfileName(options: StoreGetProfileNameOptions): Promise { const { storeHandle } = serializeArguments(options) - - return this.promisifyWithResponse((cb, cbId) => + const response = await this.promisifyWithResponse((cb, cbId) => nativeAriesAskar.askar_store_get_profile_name(storeHandle, cb, cbId) ) + + return handleInvalidNullResponse(response) } public async storeOpen(options: StoreOpenOptions): Promise { @@ -875,7 +914,7 @@ export class NodeJSAriesAskar implements AriesAskar { FFI_STORE_HANDLE ) - return new StoreHandle(handle) + return StoreHandle.fromHandle(handle) } public async storeProvision(options: StoreProvisionOptions): Promise { @@ -886,7 +925,7 @@ export class NodeJSAriesAskar implements AriesAskar { FFI_STORE_HANDLE ) - return new StoreHandle(handle) + return StoreHandle.fromHandle(handle) } public async storeRekey(options: StoreRekeyOptions): Promise { @@ -897,16 +936,22 @@ export class NodeJSAriesAskar implements AriesAskar { public async storeRemove(options: StoreRemoveOptions): Promise { const { specUri } = serializeArguments(options) + const response = await this.promisifyWithResponse( + (cb, cbId) => nativeAriesAskar.askar_store_remove(specUri, cb, cbId), + FFI_INT8 + ) - return this.promisifyWithResponse((cb, cbId) => nativeAriesAskar.askar_store_remove(specUri, cb, cbId), FFI_INT8) + return handleInvalidNullResponse(response) } public async storeRemoveProfile(options: StoreRemoveProfileOptions): Promise { const { storeHandle, profile } = serializeArguments(options) - return this.promisifyWithResponse( + const response = await this.promisifyWithResponse( (cb, cbId) => nativeAriesAskar.askar_store_remove_profile(storeHandle, profile, cb, cbId), FFI_INT8 ) + + return handleInvalidNullResponse(response) } } diff --git a/wrappers/javascript/aries-askar-nodejs/tests/store.test.ts b/wrappers/javascript/aries-askar-nodejs/tests/store.test.ts index af7fa8c5..02db78e7 100644 --- a/wrappers/javascript/aries-askar-nodejs/tests/store.test.ts +++ b/wrappers/javascript/aries-askar-nodejs/tests/store.test.ts @@ -172,7 +172,7 @@ describe('Store and Session', () => { metadata: 'updated metadata', }) - expect(key.jwkThumbprint === fetchedKey1.key.jwkThumbprint).toBeTruthy() + expect(key.jwkThumbprint === fetchedKey1?.key.jwkThumbprint).toBeTruthy() const found = await session.fetchAllKeys({ algorithm: KeyAlgs.Ed25519, @@ -184,13 +184,13 @@ describe('Store and Session', () => { await session.removeKey({ name: keyName }) - await expect(session.fetchKey({ name: keyName })).rejects.toThrowError(AriesAskarError) + await expect(session.fetchKey({ name: keyName })).resolves.toBeNull() await session.close() // Clear objects - fetchedKey1.key.handle.free() - fetchedKey2.key.handle.free() + fetchedKey1?.key.handle.free() + fetchedKey2?.key.handle.free() key.handle.free() found.forEach((entry) => entry.key.handle.free()) }) diff --git a/wrappers/javascript/aries-askar-react-native/cpp/HostObject.cpp b/wrappers/javascript/aries-askar-react-native/cpp/HostObject.cpp index 9d80348a..964b185b 100644 --- a/wrappers/javascript/aries-askar-react-native/cpp/HostObject.cpp +++ b/wrappers/javascript/aries-askar-react-native/cpp/HostObject.cpp @@ -2,13 +2,17 @@ #include #include - -AriesAskarTurboModuleHostObject::AriesAskarTurboModuleHostObject(jsi::Runtime &rt) { return; } +AriesAskarTurboModuleHostObject::AriesAskarTurboModuleHostObject( + jsi::Runtime &rt) { + return; +} FunctionMap AriesAskarTurboModuleHostObject::functionMapping(jsi::Runtime &rt) { FunctionMap fMap; fMap.insert(std::make_tuple("version", &ariesAskar::version)); fMap.insert(std::make_tuple("getCurrentError", &ariesAskar::getCurrentError)); + fMap.insert( + std::make_tuple("setDefaultLogger", &ariesAskar::setDefaultLogger)); fMap.insert(std::make_tuple("storeOpen", &ariesAskar::storeOpen)); fMap.insert( @@ -130,8 +134,8 @@ FunctionMap AriesAskarTurboModuleHostObject::functionMapping(jsi::Runtime &rt) { return fMap; } -jsi::Function AriesAskarTurboModuleHostObject::call(jsi::Runtime &rt, const char *name, - Cb cb) { +jsi::Function AriesAskarTurboModuleHostObject::call(jsi::Runtime &rt, + const char *name, Cb cb) { return jsi::Function::createFromHostFunction( rt, jsi::PropNameID::forAscii(rt, name), 1, [this, cb](jsi::Runtime &rt, const jsi::Value &thisValue, @@ -153,8 +157,9 @@ AriesAskarTurboModuleHostObject::getPropertyNames(jsi::Runtime &rt) { return result; } -jsi::Value AriesAskarTurboModuleHostObject::get(jsi::Runtime &rt, - const jsi::PropNameID &propNameId) { +jsi::Value +AriesAskarTurboModuleHostObject::get(jsi::Runtime &rt, + const jsi::PropNameID &propNameId) { auto propName = propNameId.utf8(rt); auto fMap = AriesAskarTurboModuleHostObject::functionMapping(rt); for (FunctionMap::iterator it = fMap.begin(); it != fMap.end(); ++it) { diff --git a/wrappers/javascript/aries-askar-react-native/cpp/ariesAskar.cpp b/wrappers/javascript/aries-askar-react-native/cpp/ariesAskar.cpp index 790fccef..fb7b47dc 100644 --- a/wrappers/javascript/aries-askar-react-native/cpp/ariesAskar.cpp +++ b/wrappers/javascript/aries-askar-react-native/cpp/ariesAskar.cpp @@ -16,6 +16,12 @@ jsi::Value getCurrentError(jsi::Runtime &rt, jsi::Object options) { return jsi::String::createFromAscii(rt, error); }; +jsi::Value setDefaultLogger(jsi::Runtime &rt, jsi::Object options) { + ErrorCode code = askar_set_default_logger(); + + return createReturnValue(rt, code, nullptr); +}; + jsi::Value entryListCount(jsi::Runtime &rt, jsi::Object options) { auto entryListHandle = jsiToValue(rt, options, "entryListHandle"); @@ -23,9 +29,8 @@ jsi::Value entryListCount(jsi::Runtime &rt, jsi::Object options) { int32_t out; ErrorCode code = askar_entry_list_count(entryListHandle, &out); - handleError(rt, code); - return jsi::Value(out); + return createReturnValue(rt, code, &out); }; jsi::Value entryListFree(jsi::Runtime &rt, jsi::Object options) { auto entryListHandle = @@ -33,7 +38,7 @@ jsi::Value entryListFree(jsi::Runtime &rt, jsi::Object options) { askar_entry_list_free(entryListHandle); - return jsi::Value::null(); + return createReturnValue(rt, ErrorCode::Success, nullptr); } jsi::Value entryListGetCategory(jsi::Runtime &rt, jsi::Object options) { @@ -44,9 +49,8 @@ jsi::Value entryListGetCategory(jsi::Runtime &rt, jsi::Object options) { const char *out; ErrorCode code = askar_entry_list_get_category(entryListHandle, index, &out); - handleError(rt, code); - return jsi::String::createFromAscii(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value entryListGetTags(jsi::Runtime &rt, jsi::Object options) { @@ -57,13 +61,8 @@ jsi::Value entryListGetTags(jsi::Runtime &rt, jsi::Object options) { const char *out; ErrorCode code = askar_entry_list_get_tags(entryListHandle, index, &out); - handleError(rt, code); - if (out == nullptr) { - return jsi::Value::null(); - } else { - return jsi::String::createFromAscii(rt, out); - } + return createReturnValue(rt, code, &out); } jsi::Value entryListGetValue(jsi::Runtime &rt, jsi::Object options) { @@ -74,9 +73,8 @@ jsi::Value entryListGetValue(jsi::Runtime &rt, jsi::Object options) { SecretBuffer out; ErrorCode code = askar_entry_list_get_value(entryListHandle, index, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value entryListGetName(jsi::Runtime &rt, jsi::Object options) { @@ -87,9 +85,8 @@ jsi::Value entryListGetName(jsi::Runtime &rt, jsi::Object options) { const char *out; ErrorCode code = askar_entry_list_get_name(entryListHandle, index, &out); - handleError(rt, code); - return jsi::String::createFromAscii(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value storeOpen(jsi::Runtime &rt, jsi::Object options) { @@ -108,9 +105,7 @@ jsi::Value storeOpen(jsi::Runtime &rt, jsi::Object options) { profile.length() ? profile.c_str() : nullptr, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value storeProvision(jsi::Runtime &rt, jsi::Object options) { @@ -129,9 +124,8 @@ jsi::Value storeProvision(jsi::Runtime &rt, jsi::Object options) { passKey.length() ? passKey.c_str() : nullptr, profile.length() ? profile.c_str() : nullptr, recreate, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value storeGenerateRawKey(jsi::Runtime &rt, jsi::Object options) { @@ -139,9 +133,8 @@ jsi::Value storeGenerateRawKey(jsi::Runtime &rt, jsi::Object options) { const char *out; ErrorCode code = askar_store_generate_raw_key(seed, &out); - handleError(rt, code); - return jsi::String::createFromAscii(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value storeClose(jsi::Runtime &rt, jsi::Object options) { @@ -152,9 +145,8 @@ jsi::Value storeClose(jsi::Runtime &rt, jsi::Object options) { state->rt = &rt; ErrorCode code = askar_store_close(storeHandle, callback, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value storeCreateProfile(jsi::Runtime &rt, jsi::Object options) { @@ -168,9 +160,8 @@ jsi::Value storeCreateProfile(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_store_create_profile( storeHandle, profile.length() ? profile.c_str() : nullptr, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value storeGetProfileName(jsi::Runtime &rt, jsi::Object options) { @@ -182,9 +173,8 @@ jsi::Value storeGetProfileName(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_store_get_profile_name( storeHandle, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value storeRekey(jsi::Runtime &rt, jsi::Object options) { @@ -198,9 +188,8 @@ jsi::Value storeRekey(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_store_get_profile_name( storeHandle, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value storeRemove(jsi::Runtime &rt, jsi::Object options) { @@ -212,9 +201,8 @@ jsi::Value storeRemove(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_store_remove(specUri.c_str(), callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value storeRemoveProfile(jsi::Runtime &rt, jsi::Object options) { @@ -227,9 +215,8 @@ jsi::Value storeRemoveProfile(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_store_remove_profile( storeHandle, profile.c_str(), callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionClose(jsi::Runtime &rt, jsi::Object options) { @@ -242,9 +229,8 @@ jsi::Value sessionClose(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_session_close(sessionHandle, commit, callback, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionCount(jsi::Runtime &rt, jsi::Object options) { @@ -260,9 +246,8 @@ jsi::Value sessionCount(jsi::Runtime &rt, jsi::Object options) { askar_session_count(sessionHandle, category.c_str(), tagFilter.length() ? tagFilter.c_str() : nullptr, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionFetch(jsi::Runtime &rt, jsi::Object options) { @@ -278,9 +263,8 @@ jsi::Value sessionFetch(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_session_fetch(sessionHandle, category.c_str(), name.c_str(), forUpdate, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionFetchAll(jsi::Runtime &rt, jsi::Object options) { @@ -298,9 +282,8 @@ jsi::Value sessionFetchAll(jsi::Runtime &rt, jsi::Object options) { sessionHandle, category.c_str(), tagFilter.length() ? tagFilter.c_str() : nullptr, limit, forUpdate, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionFetchAllKeys(jsi::Runtime &rt, jsi::Object options) { @@ -320,9 +303,8 @@ jsi::Value sessionFetchAllKeys(jsi::Runtime &rt, jsi::Object options) { thumbprint.length() ? thumbprint.c_str() : nullptr, tagFilter.length() ? tagFilter.c_str() : nullptr, limit, forUpdate, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionFetchKey(jsi::Runtime &rt, jsi::Object options) { @@ -337,9 +319,8 @@ jsi::Value sessionFetchKey(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_session_fetch_key(sessionHandle, name.c_str(), forUpdate, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionInsertKey(jsi::Runtime &rt, jsi::Object options) { @@ -360,9 +341,8 @@ jsi::Value sessionInsertKey(jsi::Runtime &rt, jsi::Object options) { metadata.length() ? metadata.c_str() : nullptr, tags.length() ? tags.c_str() : nullptr, expiryMs, callback, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionRemoveAll(jsi::Runtime &rt, jsi::Object options) { @@ -379,9 +359,7 @@ jsi::Value sessionRemoveAll(jsi::Runtime &rt, jsi::Object options) { tagFilter.length() ? tagFilter.c_str() : nullptr, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionRemoveKey(jsi::Runtime &rt, jsi::Object options) { @@ -395,9 +373,7 @@ jsi::Value sessionRemoveKey(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_session_remove_key(sessionHandle, name.c_str(), callback, CallbackId(state)); - handleError(rt, code); - - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionStart(jsi::Runtime &rt, jsi::Object options) { @@ -413,9 +389,7 @@ jsi::Value sessionStart(jsi::Runtime &rt, jsi::Object options) { storeHandle, profile.length() ? profile.c_str() : nullptr, asTransaction, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionUpdate(jsi::Runtime &rt, jsi::Object options) { @@ -436,9 +410,7 @@ jsi::Value sessionUpdate(jsi::Runtime &rt, jsi::Object options) { tags.length() ? tags.c_str() : nullptr, expiryMs, callback, CallbackId(state)); - handleError(rt, code); - - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value sessionUpdateKey(jsi::Runtime &rt, jsi::Object options) { @@ -458,9 +430,7 @@ jsi::Value sessionUpdateKey(jsi::Runtime &rt, jsi::Object options) { tags.length() ? tags.c_str() : nullptr, expiryMs, callback, CallbackId(state)); - handleError(rt, code); - - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); } jsi::Value scanStart(jsi::Runtime &rt, jsi::Object options) { @@ -480,9 +450,8 @@ jsi::Value scanStart(jsi::Runtime &rt, jsi::Object options) { storeHandle, profile.length() ? profile.c_str() : nullptr, category.c_str(), tagFilter.length() ? tagFilter.c_str() : nullptr, offset, limit, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); }; jsi::Value scanNext(jsi::Runtime &rt, jsi::Object options) { @@ -494,18 +463,16 @@ jsi::Value scanNext(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_scan_next(scanHandle, callbackWithResponse, CallbackId(state)); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); }; jsi::Value scanFree(jsi::Runtime &rt, jsi::Object options) { auto scanHandle = jsiToValue(rt, options, "scanHandle"); ErrorCode code = askar_scan_free(scanHandle); - handleError(rt, code); - return jsi::Value::null(); + return createReturnValue(rt, code, nullptr); }; jsi::Value keyFromJwk(jsi::Runtime &rt, jsi::Object options) { @@ -514,11 +481,8 @@ jsi::Value keyFromJwk(jsi::Runtime &rt, jsi::Object options) { LocalKeyHandle out; ErrorCode code = askar_key_from_jwk(jwk, &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); } jsi::Value keyFromKeyExchange(jsi::Runtime &rt, jsi::Object options) { @@ -530,11 +494,8 @@ jsi::Value keyFromKeyExchange(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_from_key_exchange(algorithm.c_str(), skHandle, pkHandle, &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); } jsi::Value keyFromPublicBytes(jsi::Runtime &rt, jsi::Object options) { @@ -545,11 +506,8 @@ jsi::Value keyFromPublicBytes(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_from_public_bytes(algorithm.c_str(), publicKey, &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); } jsi::Value keyFromSecretBytes(jsi::Runtime &rt, jsi::Object options) { @@ -560,11 +518,8 @@ jsi::Value keyFromSecretBytes(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_from_secret_bytes(algorithm.c_str(), secretKey, &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); } jsi::Value keyFromSeed(jsi::Runtime &rt, jsi::Object options) { @@ -576,26 +531,19 @@ jsi::Value keyFromSeed(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_from_seed(algorithm.c_str(), seed, method.c_str(), &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); } jsi::Value keyGenerate(jsi::Runtime &rt, jsi::Object options) { auto algorithm = jsiToValue(rt, options, "algorithm"); - // auto ephemeral = jsiToValue(rt, options, "ephemeral"); - auto ephemeral = 0; + auto ephemeral = jsiToValue(rt, options, "ephemeral"); LocalKeyHandle out; ErrorCode code = askar_key_generate(algorithm.c_str(), ephemeral, &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); } jsi::Value keyGetAlgorithm(jsi::Runtime &rt, jsi::Object options) { @@ -605,9 +553,8 @@ jsi::Value keyGetAlgorithm(jsi::Runtime &rt, jsi::Object options) { const char *out; ErrorCode code = askar_key_get_algorithm(localKeyHandle, &out); - handleError(rt, code); - return jsi::String::createFromAscii(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyGetEphemeral(jsi::Runtime &rt, jsi::Object options) { @@ -617,9 +564,8 @@ jsi::Value keyGetEphemeral(jsi::Runtime &rt, jsi::Object options) { int8_t out; ErrorCode code = askar_key_get_ephemeral(localKeyHandle, &out); - handleError(rt, code); - return jsi::Value(int(out)); + return createReturnValue(rt, code, &out); } jsi::Value keyGetJwkPublic(jsi::Runtime &rt, jsi::Object options) { @@ -631,9 +577,8 @@ jsi::Value keyGetJwkPublic(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_get_jwk_public(localKeyHandle, algorithm.c_str(), &out); - handleError(rt, code); - return jsi::String::createFromAscii(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyGetJwkSecret(jsi::Runtime &rt, jsi::Object options) { @@ -643,9 +588,8 @@ jsi::Value keyGetJwkSecret(jsi::Runtime &rt, jsi::Object options) { SecretBuffer out; ErrorCode code = askar_key_get_jwk_secret(localKeyHandle, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyGetJwkThumbprint(jsi::Runtime &rt, jsi::Object options) { @@ -657,9 +601,8 @@ jsi::Value keyGetJwkThumbprint(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_get_jwk_thumbprint(localKeyHandle, algorithm.c_str(), &out); - handleError(rt, code); - return jsi::String::createFromAscii(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyGetPublicBytes(jsi::Runtime &rt, jsi::Object options) { @@ -669,9 +612,8 @@ jsi::Value keyGetPublicBytes(jsi::Runtime &rt, jsi::Object options) { SecretBuffer out; ErrorCode code = askar_key_get_public_bytes(localKeyHandle, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyGetSecretBytes(jsi::Runtime &rt, jsi::Object options) { @@ -681,9 +623,8 @@ jsi::Value keyGetSecretBytes(jsi::Runtime &rt, jsi::Object options) { SecretBuffer out; ErrorCode code = askar_key_get_secret_bytes(localKeyHandle, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keySignMessage(jsi::Runtime &rt, jsi::Object options) { @@ -697,9 +638,8 @@ jsi::Value keySignMessage(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_sign_message( localKeyHandle, message, sigType.length() ? sigType.c_str() : nullptr, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyUnwrapKey(jsi::Runtime &rt, jsi::Object options) { @@ -714,11 +654,8 @@ jsi::Value keyUnwrapKey(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_unwrap_key(localKeyHandle, algorithm.c_str(), ciphertext, nonce, tag, &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); } jsi::Value keyVerifySignature(jsi::Runtime &rt, jsi::Object options) { @@ -733,9 +670,8 @@ jsi::Value keyVerifySignature(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_verify_signature( localKeyHandle, message, signature, sigType.length() ? sigType.c_str() : nullptr, &out); - handleError(rt, code); - return jsi::Value(int(out)); + return createReturnValue(rt, code, &out); } jsi::Value keyWrapKey(jsi::Runtime &rt, jsi::Object options) { @@ -747,14 +683,8 @@ jsi::Value keyWrapKey(jsi::Runtime &rt, jsi::Object options) { EncryptedBuffer out; ErrorCode code = askar_key_wrap_key(localKeyHandle, other, nonce, &out); - handleError(rt, code); - auto object = jsi::Object(rt); - object.setProperty(rt, "buffer", secretBufferToArrayBuffer(rt, out.buffer)); - object.setProperty(rt, "tagPos", int(out.tag_pos)); - object.setProperty(rt, "noncePos", int(out.nonce_pos)); - - return object; + return createReturnValue(rt, code, &out); } jsi::Value keyConvert(jsi::Runtime &rt, jsi::Object options) { @@ -765,11 +695,8 @@ jsi::Value keyConvert(jsi::Runtime &rt, jsi::Object options) { LocalKeyHandle out; ErrorCode code = askar_key_convert(localKeyHandle, algorithm.c_str(), &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); }; jsi::Value keyFree(jsi::Runtime &rt, jsi::Object options) { @@ -778,7 +705,7 @@ jsi::Value keyFree(jsi::Runtime &rt, jsi::Object options) { askar_key_free(localKeyHandle); - return jsi::Value::null(); + return createReturnValue(rt, ErrorCode::Success, nullptr); }; jsi::Value keyCryptoBox(jsi::Runtime &rt, jsi::Object options) { @@ -791,9 +718,8 @@ jsi::Value keyCryptoBox(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_crypto_box(recipientKey, senderKey, message, nonce, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyCryptoBoxOpen(jsi::Runtime &rt, jsi::Object options) { @@ -806,18 +732,16 @@ jsi::Value keyCryptoBoxOpen(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_crypto_box_open(recipientKey, senderKey, message, nonce, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyCryptoBoxRandomNonce(jsi::Runtime &rt, jsi::Object options) { SecretBuffer out; ErrorCode code = askar_key_crypto_box_random_nonce(&out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyCryptoBoxSeal(jsi::Runtime &rt, jsi::Object options) { @@ -828,9 +752,8 @@ jsi::Value keyCryptoBoxSeal(jsi::Runtime &rt, jsi::Object options) { SecretBuffer out; ErrorCode code = askar_key_crypto_box_seal(localKeyHandle, message, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyCryptoBoxSealOpen(jsi::Runtime &rt, jsi::Object options) { @@ -842,9 +765,8 @@ jsi::Value keyCryptoBoxSealOpen(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_crypto_box_seal_open(localKeyHandle, ciphertext, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyDeriveEcdh1pu(jsi::Runtime &rt, jsi::Object options) { @@ -863,11 +785,8 @@ jsi::Value keyDeriveEcdh1pu(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_derive_ecdh_1pu(algorithm.c_str(), ephemeralKey, senderKey, recipientKey, algId, apu, apv, ccTag, receive, &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); } jsi::Value keyDeriveEcdhEs(jsi::Runtime &rt, jsi::Object options) { @@ -884,11 +803,8 @@ jsi::Value keyDeriveEcdhEs(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_derive_ecdh_es(algorithm.c_str(), ephemeralKey, recipientKey, algId, apu, apv, receive, &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); } jsi::Value keyAeadDecrypt(jsi::Runtime &rt, jsi::Object options) { @@ -903,9 +819,8 @@ jsi::Value keyAeadDecrypt(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_aead_decrypt(localKeyHandle, ciphertext, nonce, tag, aad, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyAeadEncrypt(jsi::Runtime &rt, jsi::Object options) { @@ -919,14 +834,8 @@ jsi::Value keyAeadEncrypt(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_aead_encrypt(localKeyHandle, message, nonce, aad, &out); - handleError(rt, code); - - auto object = jsi::Object(rt); - object.setProperty(rt, "buffer", secretBufferToArrayBuffer(rt, out.buffer)); - object.setProperty(rt, "tagPos", int(out.tag_pos)); - object.setProperty(rt, "noncePos", int(out.nonce_pos)); - return object; + return createReturnValue(rt, code, &out); } jsi::Value keyAeadGetPadding(jsi::Runtime &rt, jsi::Object options) { @@ -938,9 +847,8 @@ jsi::Value keyAeadGetPadding(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_aead_get_padding(localKeyHandle, messageLength, &out); - handleError(rt, code); - return jsi::Value(out); + return createReturnValue(rt, code, &out); } jsi::Value keyAeadGetParams(jsi::Runtime &rt, jsi::Object options) { @@ -950,13 +858,8 @@ jsi::Value keyAeadGetParams(jsi::Runtime &rt, jsi::Object options) { AeadParams out; ErrorCode code = askar_key_aead_get_params(localKeyHandle, &out); - handleError(rt, code); - - auto object = jsi::Object(rt); - object.setProperty(rt, "nonceLength", out.nonce_length); - object.setProperty(rt, "tagLength", out.tag_length); - return object; + return createReturnValue(rt, code, &out); } jsi::Value keyAeadRandomNonce(jsi::Runtime &rt, jsi::Object options) { @@ -966,9 +869,8 @@ jsi::Value keyAeadRandomNonce(jsi::Runtime &rt, jsi::Object options) { SecretBuffer out; ErrorCode code = askar_key_aead_random_nonce(localKeyHandle, &out); - handleError(rt, code); - return secretBufferToArrayBuffer(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyEntryListCount(jsi::Runtime &rt, jsi::Object options) { @@ -978,9 +880,8 @@ jsi::Value keyEntryListCount(jsi::Runtime &rt, jsi::Object options) { int32_t out; ErrorCode code = askar_key_entry_list_count(keyEntryListHandle, &out); - handleError(rt, code); - return jsi::Value(out); + return createReturnValue(rt, code, &out); } jsi::Value keyEntryListFree(jsi::Runtime &rt, jsi::Object options) { @@ -990,9 +891,8 @@ jsi::Value keyEntryListFree(jsi::Runtime &rt, jsi::Object options) { int32_t out; ErrorCode code = askar_key_entry_list_count(keyEntryListHandle, &out); - handleError(rt, code); - return jsi::Value(out); + return createReturnValue(rt, code, &out); } jsi::Value keyEntryListGetAlgorithm(jsi::Runtime &rt, jsi::Object options) { @@ -1004,9 +904,8 @@ jsi::Value keyEntryListGetAlgorithm(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_entry_list_get_algorithm(keyEntryListHandle, index, &out); - handleError(rt, code); - return jsi::String::createFromAscii(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyEntryListGetMetadata(jsi::Runtime &rt, jsi::Object options) { @@ -1018,13 +917,8 @@ jsi::Value keyEntryListGetMetadata(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_entry_list_get_metadata(keyEntryListHandle, index, &out); - handleError(rt, code); - if (out == nullptr) { - return jsi::Value::null(); - } else { - return jsi::String::createFromAscii(rt, out); - } + return createReturnValue(rt, code, &out); } jsi::Value keyEntryListGetName(jsi::Runtime &rt, jsi::Object options) { @@ -1036,9 +930,8 @@ jsi::Value keyEntryListGetName(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_entry_list_get_name(keyEntryListHandle, index, &out); - handleError(rt, code); - return jsi::String::createFromAscii(rt, out); + return createReturnValue(rt, code, &out); } jsi::Value keyEntryListGetTags(jsi::Runtime &rt, jsi::Object options) { @@ -1050,13 +943,8 @@ jsi::Value keyEntryListGetTags(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_entry_list_get_tags(keyEntryListHandle, index, &out); - handleError(rt, code); - if (out == nullptr) { - return jsi::Value::null(); - } else { - return jsi::String::createFromAscii(rt, out); - } + return createReturnValue(rt, code, &out); } jsi::Value keyEntryListLoadLocal(jsi::Runtime &rt, jsi::Object options) { @@ -1068,11 +956,8 @@ jsi::Value keyEntryListLoadLocal(jsi::Runtime &rt, jsi::Object options) { ErrorCode code = askar_key_entry_list_load_local(keyEntryListHandle, index, &out); - handleError(rt, code); - auto serializedPointer = std::to_string(intptr_t(out._0)); - jsi::String pointer = jsi::String::createFromAscii(rt, serializedPointer); - return pointer; + return createReturnValue(rt, code, &out); } } // namespace ariesAskar diff --git a/wrappers/javascript/aries-askar-react-native/cpp/ariesAskar.h b/wrappers/javascript/aries-askar-react-native/cpp/ariesAskar.h index 2ab5ed9c..5b2c7680 100644 --- a/wrappers/javascript/aries-askar-react-native/cpp/ariesAskar.h +++ b/wrappers/javascript/aries-askar-react-native/cpp/ariesAskar.h @@ -11,11 +11,10 @@ namespace ariesAskar { jsi::Value version(jsi::Runtime &rt, jsi::Object options); jsi::Value getCurrentError(jsi::Runtime &rt, jsi::Object options); - +jsi::Value setDefaultLogger(jsi::Runtime &rt, jsi::Object options); // TODO: not implemented yet // jsi::Value setCustomLogger(jsi::Runtime &rt, jsi::Object options); -// jsi::Value setDefaultLogger(jsi::Runtime &rt, jsi::Object options); // jsi::Value setMaxLogLevel(jsi::Runtime &rt, jsi::Object options); // jsi::Value clearCustomLogger(jsi::Runtime &rt, jsi::Object options); diff --git a/wrappers/javascript/aries-askar-react-native/cpp/turboModuleUtility.cpp b/wrappers/javascript/aries-askar-react-native/cpp/turboModuleUtility.cpp index a57e77f7..f47b1c10 100644 --- a/wrappers/javascript/aries-askar-react-native/cpp/turboModuleUtility.cpp +++ b/wrappers/javascript/aries-askar-react-native/cpp/turboModuleUtility.cpp @@ -23,23 +23,271 @@ void registerTurboModule(jsi::Runtime &rt, void assertValueIsObject(jsi::Runtime &rt, const jsi::Value *val) { val->asObject(rt); } -void handleError(jsi::Runtime &rt, ErrorCode code) { - if (code == ErrorCode::Success) - return; - - jsi::Value errorMessage = ariesAskar::getCurrentError(rt, jsi::Object(rt)); - - jsi::Object JSON = rt.global().getPropertyAsObject(rt, "JSON"); - jsi::Function JSONParse = JSON.getPropertyAsFunction(rt, "parse"); - jsi::Object parsedErrorObject = - JSONParse.call(rt, errorMessage).getObject(rt); - jsi::Value message = parsedErrorObject.getProperty(rt, "message"); - if (message.isString()) { - throw jsi::JSError(rt, message.getString(rt).utf8(rt)); + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + const char **value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + auto isNullptr = value == nullptr || *value == nullptr; + auto valueWithoutNullptr = isNullptr + ? jsi::Value::null() + : jsi::String::createFromAscii(rt, *value); + object.setProperty(rt, "value", valueWithoutNullptr); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + const char *const *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + auto isNullptr = value == nullptr || *value == nullptr; + auto valueWithoutNullptr = isNullptr + ? jsi::Value::null() + : jsi::String::createFromAscii(rt, *value); + object.setProperty(rt, "value", valueWithoutNullptr); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + nullptr_t value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + object.setProperty(rt, "value", jsi::Value::null()); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, int8_t *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + auto valueWithoutNullptr = + value == nullptr ? jsi::Value::null() : jsi::Value(rt, int(*value)); + object.setProperty(rt, "value", valueWithoutNullptr); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + int8_t const *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + auto valueWithoutNullptr = + value == nullptr ? jsi::Value::null() : jsi::Value(rt, int(*value)); + object.setProperty(rt, "value", valueWithoutNullptr); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, int32_t *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + auto valueWithoutNullptr = + value == nullptr ? jsi::Value::null() : jsi::Value(rt, int(*value)); + object.setProperty(rt, "value", valueWithoutNullptr); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, int64_t *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + auto valueWithoutNullptr = + value == nullptr ? jsi::Value::null() : jsi::Value(rt, int(*value)); + object.setProperty(rt, "value", valueWithoutNullptr); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + int64_t const *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + auto valueWithoutNullptr = + value == nullptr ? jsi::Value::null() : jsi::Value(rt, int(*value)); + object.setProperty(rt, "value", valueWithoutNullptr); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + size_t const *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + auto valueWithoutNullptr = + value == nullptr ? jsi::Value::null() : jsi::Value(rt, int(*value)); + object.setProperty(rt, "value", valueWithoutNullptr); } - throw jsi::JSError(rt, "Could not get message with code: " + - std::to_string(code)); -}; + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + intptr_t *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + auto valueWithoutNullptr = + value == nullptr ? jsi::Value::null() : jsi::Value(int(*value)); + object.setProperty(rt, "value", valueWithoutNullptr); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + std::string value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + object.setProperty(rt, "value", jsi::String::createFromAscii(rt, value)); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + SecretBuffer *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + auto valueWithoutNullptr = value == nullptr + ? jsi::Value::null() + : secretBufferToArrayBuffer(rt, *value); + object.setProperty(rt, "value", valueWithoutNullptr); + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + LocalKeyHandle *value) { + auto isNullptr = value == nullptr || value->_0 == nullptr; + return isNullptr + ? createReturnValue(rt, code, nullptr) + : createReturnValue(rt, code, std::to_string(intptr_t(value->_0))); +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + EntryListHandle const *value) { + auto isNullptr = value == nullptr || value->_0 == nullptr; + return isNullptr + ? createReturnValue(rt, code, nullptr) + : createReturnValue(rt, code, std::to_string(intptr_t(value->_0))); +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + KeyEntryListHandle const *value) { + auto isNullptr = value == nullptr || value->_0 == nullptr; + return isNullptr + ? createReturnValue(rt, code, nullptr) + : createReturnValue(rt, code, std::to_string(intptr_t(value->_0))); +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + EncryptedBuffer *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + if (value == nullptr) { + object.setProperty(rt, "value", jsi::Value::null()); + } else { + auto valueObject = jsi::Object(rt); + + valueObject.setProperty(rt, "buffer", + secretBufferToArrayBuffer(rt, value->buffer)); + valueObject.setProperty(rt, "tagPos", int(value->tag_pos)); + valueObject.setProperty(rt, "noncePos", int(value->nonce_pos)); + + object.setProperty(rt, "value", valueObject); + } + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} + +template <> +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, + AeadParams *value) { + auto object = jsi::Object(rt); + + if (code == ErrorCode::Success) { + if (value == nullptr) { + object.setProperty(rt, "value", jsi::Value::null()); + } else { + auto valueObject = jsi::Object(rt); + + valueObject.setProperty(rt, "nonceLength", int(value->nonce_length)); + valueObject.setProperty(rt, "tagLength", int(value->tag_length)); + + object.setProperty(rt, "value", object); + } + } + + object.setProperty(rt, "errorCode", int(code)); + + return object; +} void callback(CallbackId result, ErrorCode code) { invoker->invokeAsync([result, code]() { @@ -47,7 +295,10 @@ void callback(CallbackId result, ErrorCode code) { State *state = static_cast(_state); jsi::Function *cb = &state->cb; jsi::Runtime *rt = reinterpret_cast(state->rt); - cb->call(*rt, int(code)); + + auto object = jsi::Object(*rt); + object.setProperty(*rt, "errorCode", int(code)); + cb->call(*rt, object); }); // delete state; } @@ -60,7 +311,9 @@ void callbackWithResponse(CallbackId result, ErrorCode code, size_t response) { State *state = static_cast(_state); jsi::Function *cb = &state->cb; jsi::Runtime *rt = reinterpret_cast(state->rt); - cb->call(*rt, int(code), int(response)); + + auto out = createReturnValue(*rt, code, &response); + cb->call(*rt, out); }); } @@ -72,9 +325,9 @@ void callbackWithResponse(CallbackId result, ErrorCode code, State *state = static_cast(_state); jsi::Function *cb = &state->cb; jsi::Runtime *rt = reinterpret_cast(state->rt); - jsi::String serializedResponse = - jsi::String::createFromAscii(*rt, response ? response : "PANIC"); - cb->call(*rt, int(code), serializedResponse); + + auto out = createReturnValue(*rt, code, &response); + cb->call(*rt, out); }); } @@ -87,10 +340,8 @@ void callbackWithResponse(CallbackId result, ErrorCode code, jsi::Function *cb = &state->cb; jsi::Runtime *rt = reinterpret_cast(state->rt); - std::string serializedPointer = std::to_string(intptr_t(response._0)); - jsi::String pointer = jsi::String::createFromAscii(*rt, serializedPointer); - - cb->call(*rt, int(code), serializedPointer); + auto out = createReturnValue(*rt, code, &response); + cb->call(*rt, out); }); } @@ -103,10 +354,8 @@ void callbackWithResponse(CallbackId result, ErrorCode code, jsi::Function *cb = &state->cb; jsi::Runtime *rt = reinterpret_cast(state->rt); - std::string serializedPointer = std::to_string(intptr_t(response._0)); - jsi::String pointer = jsi::String::createFromAscii(*rt, serializedPointer); - - cb->call(*rt, int(code), serializedPointer); + auto out = createReturnValue(*rt, code, &response); + cb->call(*rt, out); }); } @@ -117,7 +366,9 @@ void callbackWithResponse(CallbackId result, ErrorCode code, int8_t response) { State *state = static_cast(_state); jsi::Function *cb = &state->cb; jsi::Runtime *rt = reinterpret_cast(state->rt); - cb->call(*rt, int(code), int(response)); + + auto out = createReturnValue(*rt, code, &response); + cb->call(*rt, out); }); } @@ -128,7 +379,9 @@ void callbackWithResponse(CallbackId result, ErrorCode code, int64_t response) { State *state = static_cast(_state); jsi::Function *cb = &state->cb; jsi::Runtime *rt = reinterpret_cast(state->rt); - cb->call(*rt, int(code), int(response)); + + auto out = createReturnValue(*rt, code, &response); + cb->call(*rt, out); }); } @@ -320,7 +573,6 @@ jsi::ArrayBuffer secretBufferToArrayBuffer(jsi::Runtime &rt, SecretBuffer sb) { .getObject(rt) .getArrayBuffer(rt); - // TODO: signature here is weird. sb.data cannot go into ab.data() memcpy(arrayBuffer.data(rt), sb.data, sb.len); return arrayBuffer; } diff --git a/wrappers/javascript/aries-askar-react-native/cpp/turboModuleUtility.h b/wrappers/javascript/aries-askar-react-native/cpp/turboModuleUtility.h index 663be9ba..f97db934 100644 --- a/wrappers/javascript/aries-askar-react-native/cpp/turboModuleUtility.h +++ b/wrappers/javascript/aries-askar-react-native/cpp/turboModuleUtility.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include #include @@ -33,9 +33,6 @@ template T jsiToValue(jsi::Runtime &rt, jsi::Object &options, const char *name, bool optional = false); -// Handles an error from within the module and sends it back to the js side -void handleError(jsi::Runtime &rt, ErrorCode code); - // Callback function that makes the host function async void callback(CallbackId result, ErrorCode code); @@ -44,6 +41,20 @@ void callback(CallbackId result, ErrorCode code); template void callbackWithResponse(CallbackId result, ErrorCode code, T response); +// Instantiate a return object for JS side. +// ```typescript +// type ReturnObject = { +// errorCode: number +// value?: unknown | null +// } +// ``` +// +// Value will be defined if there is no error. +// Value will be `null` if there is no value to return +// Value will be undefined if there is an error, e.g. error code != 0 +template +jsi::Value createReturnValue(jsi::Runtime &rt, ErrorCode code, T out); + jsi::ArrayBuffer byteBufferToArrayBuffer(jsi::Runtime &rt, ByteBuffer bb); jsi::ArrayBuffer secretBufferToArrayBuffer(jsi::Runtime &rt, SecretBuffer sb); diff --git a/wrappers/javascript/aries-askar-react-native/native/aries_askar.node b/wrappers/javascript/aries-askar-react-native/native/aries_askar.node index cb6cc59f..ee9b5b34 100644 --- a/wrappers/javascript/aries-askar-react-native/native/aries_askar.node +++ b/wrappers/javascript/aries-askar-react-native/native/aries_askar.node @@ -1,4 +1,4 @@ # This is a placeholder file to prevent node-pre-gyp from installing the # aries-askar binary when cloning this repository. It won't be published to # NPM, meaning when you download this package from npm it will try to download -# the binary. +# the binary. \ No newline at end of file diff --git a/wrappers/javascript/aries-askar-react-native/src/ReactNativeAriesAskar.ts b/wrappers/javascript/aries-askar-react-native/src/ReactNativeAriesAskar.ts index 3fa5249b..25a595e4 100644 --- a/wrappers/javascript/aries-askar-react-native/src/ReactNativeAriesAskar.ts +++ b/wrappers/javascript/aries-askar-react-native/src/ReactNativeAriesAskar.ts @@ -1,5 +1,7 @@ +import type { Callback, CallbackWithResponse } from './utils' import type { AriesAskar, + AriesAskarErrorObject, EntryListCountOptions, EntryListFreeOptions, EntryListGetCategoryOptions, @@ -72,6 +74,8 @@ import type { } from '@hyperledger/aries-askar-shared' import { + AriesAskarError, + handleInvalidNullResponse, AeadParams, EncryptedBuffer, LocalKeyHandle, @@ -83,33 +87,38 @@ import { } from '@hyperledger/aries-askar-shared' import { ariesAskarReactNative } from './library' -import { serializeArguments } from './utils' +import { handleError, serializeArguments } from './utils' export class ReactNativeAriesAskar implements AriesAskar { - private promisify = (method: (cb: (err: number) => void) => void): Promise => { + private promisify = (method: (cb: Callback) => void): Promise => { return new Promise((resolve, reject) => { - const _cb = (err: number) => { - if (err !== 0) reject(this.getCurrentError()) - resolve() + const _cb: Callback = ({ errorCode }) => { + if (errorCode !== 0) { + reject(new AriesAskarError(JSON.parse(this.getCurrentError()) as AriesAskarErrorObject)) + } else { + resolve() + } } method(_cb) }) } - private promisifyWithResponse = ( - method: (cb: (err: number, response: Response) => void) => void - ): Promise => { + private promisifyWithResponse = ( + method: (cb: CallbackWithResponse) => void + ): Promise => { return new Promise((resolve, reject) => { - const _cb = (err: number, response: Response) => { - if (err !== 0) reject(this.getCurrentError()) - - switch (typeof response) { - case 'string': - resolve(response as unknown as Return) - break - default: - resolve(response as unknown as Return) + const _cb: CallbackWithResponse = ({ errorCode, value }) => { + if (errorCode !== 0) { + reject(new AriesAskarError(JSON.parse(this.getCurrentError()) as AriesAskarErrorObject)) + } else { + if (value === undefined) { + reject( + AriesAskarError.customError({ message: 'error code was 0 but no value found. This should not occur.' }) + ) + } else { + resolve(value) + } } } method(_cb) @@ -117,485 +126,529 @@ export class ReactNativeAriesAskar implements AriesAskar { } public version(): string { - return ariesAskarReactNative.version({}) + return handleInvalidNullResponse(ariesAskarReactNative.version({})) } public getCurrentError(): string { - return ariesAskarReactNative.getCurrentError({}) + return handleInvalidNullResponse(ariesAskarReactNative.getCurrentError({})) } public clearCustomLogger(): void { throw new Error('Method not implemented. clearCustomLogger') } - public setCustomLogger(options: SetCustomLoggerOptions): void { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public setCustomLogger(_: SetCustomLoggerOptions): void { throw new Error('Method not implemented. setCustomLogger') } public setDefaultLogger(): void { - throw new Error('Method not implemented. setDefaultLogger') + ariesAskarReactNative.setDefaultLogger({}) } - public setMaxLogLevel(options: SetMaxLogLevelOptions): void { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public setMaxLogLevel(_: SetMaxLogLevelOptions): void { throw new Error('Method not implemented. setMaxLogLevel') } public entryListCount(options: EntryListCountOptions): number { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.entryListCount(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.entryListCount(serializedOptions))) } public entryListFree(options: EntryListFreeOptions): void { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.entryListFree(serializedOptions) + + // null resopnse is expected as we're freeing the object + handleError(ariesAskarReactNative.entryListFree(serializedOptions)) } public entryListGetCategory(options: EntryListGetCategoryOptions): string { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.entryListGetCategory(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.entryListGetCategory(serializedOptions))) } public entryListGetName(options: EntryListGetNameOptions): string { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.entryListGetName(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.entryListGetName(serializedOptions))) } - public entryListGetTags(options: EntryListGetTagsOptions): string { + public entryListGetTags(options: EntryListGetTagsOptions): string | null { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.entryListGetTags(serializedOptions) + return handleError(ariesAskarReactNative.entryListGetTags(serializedOptions)) } public entryListGetValue(options: EntryListGetValueOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.entryListGetValue(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.entryListGetValue(serializedOptions))) return new Uint8Array(buf) } public keyAeadDecrypt(options: KeyAeadDecryptOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.keyAeadDecrypt(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyAeadDecrypt(serializedOptions))) return new Uint8Array(buf) } public keyAeadEncrypt(options: KeyAeadEncryptOptions): EncryptedBuffer { const serializedOptions = serializeArguments(options) - const { buffer, noncePos, tagPos } = ariesAskarReactNative.keyAeadEncrypt(serializedOptions) + const ret = handleError(ariesAskarReactNative.keyAeadEncrypt(serializedOptions)) + + const { buffer, noncePos, tagPos } = handleInvalidNullResponse(ret) return new EncryptedBuffer({ tagPos, noncePos, buffer: new Uint8Array(buffer) }) } public keyAeadGetPadding(options: KeyAeadGetPaddingOptions): number { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.keyAeadGetPadding(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.keyAeadGetPadding(serializedOptions))) } public keyAeadGetParams(options: KeyAeadGetParamsOptions): AeadParams { const serializedOptions = serializeArguments(options) - const { tagLength, nonceLength } = ariesAskarReactNative.keyAeadGetParams(serializedOptions) + const ret = handleError(ariesAskarReactNative.keyAeadGetParams(serializedOptions)) + + const { tagLength, nonceLength } = handleInvalidNullResponse(ret) return new AeadParams({ nonceLength, tagLength }) } public keyAeadRandomNonce(options: KeyAeadRandomNonceOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.keyAeadRandomNonce(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyAeadRandomNonce(serializedOptions))) return new Uint8Array(buf) } public keyConvert(options: KeyConvertOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyConvert(serializedOptions) + const handle = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyConvert(serializedOptions))) return new LocalKeyHandle(handle) } public keyCryptoBox(options: KeyCryptoBoxOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.keyCryptoBox(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyCryptoBox(serializedOptions))) return new Uint8Array(buf) } public keyCryptoBoxOpen(options: KeyCryptoBoxOpenOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.keyCryptoBoxOpen(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyCryptoBoxOpen(serializedOptions))) return new Uint8Array(buf) } public keyCryptoBoxRandomNonce(): Uint8Array { - const buf = ariesAskarReactNative.keyCryptoBoxRandomNonce({}) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyCryptoBoxRandomNonce({}))) return new Uint8Array(buf) } public keyCryptoBoxSeal(options: KeyCryptoBoxSealOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.keyCryptoBoxSeal(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyCryptoBoxSeal(serializedOptions))) return new Uint8Array(buf) } public keyCryptoBoxSealOpen(options: KeyCryptoBoxSealOpenOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.keyCryptoBoxSealOpen(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyCryptoBoxSealOpen(serializedOptions))) return new Uint8Array(buf) } public keyDeriveEcdh1pu(options: KeyDeriveEcdh1puOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyDeriveEcdh1pu(serializedOptions) + const handle = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyDeriveEcdh1pu(serializedOptions))) return new LocalKeyHandle(handle) } public keyDeriveEcdhEs(options: KeyDeriveEcdhEsOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyDeriveEcdhEs(serializedOptions) + const handle = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyDeriveEcdhEs(serializedOptions))) return new LocalKeyHandle(handle) } public keyEntryListCount(options: KeyEntryListCountOptions): number { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.keyEntryListCount(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.keyEntryListCount(serializedOptions))) } public keyEntryListFree(options: KeyEntryListFreeOptions): void { const serializedOptions = serializeArguments(options) - ariesAskarReactNative.keyEntryListFree(serializedOptions) + + // null resopnse is expected as we're freeing the object + handleError(ariesAskarReactNative.keyEntryListFree(serializedOptions)) } public keyEntryListGetAlgorithm(options: KeyEntryListGetAlgorithmOptions): string { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.keyEntryListGetAlgorithm(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.keyEntryListGetAlgorithm(serializedOptions))) } - public keyEntryListGetMetadata(options: KeyEntryListGetMetadataOptions): string { + public keyEntryListGetMetadata(options: KeyEntryListGetMetadataOptions): string | null { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.keyEntryListGetMetadata(serializedOptions) + return handleError(ariesAskarReactNative.keyEntryListGetMetadata(serializedOptions)) } public keyEntryListGetName(options: KeyEntryListGetNameOptions): string { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.keyEntryListGetName(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.keyEntryListGetName(serializedOptions))) } - public keyEntryListGetTags(options: KeyEntryListGetTagsOptions): string { + public keyEntryListGetTags(options: KeyEntryListGetTagsOptions): string | null { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.keyEntryListGetTags(serializedOptions) + return handleError(ariesAskarReactNative.keyEntryListGetTags(serializedOptions)) } public keyEntryListLoadLocal(options: KeyEntryListLoadLocalOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyEntryListLoadLocal(serializedOptions) + const handle = handleInvalidNullResponse( + handleError(ariesAskarReactNative.keyEntryListLoadLocal(serializedOptions)) + ) return new LocalKeyHandle(handle) } public keyFree(options: KeyFreeOptions): void { const serializedOptions = serializeArguments(options) - ariesAskarReactNative.keyFree(serializedOptions) + + // null resopnse is expected as we're freeing the object + handleError(ariesAskarReactNative.keyFree(serializedOptions)) } public keyFromJwk(options: KeyFromJwkOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyFromJwk(serializedOptions) + const handle = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyFromJwk(serializedOptions))) return new LocalKeyHandle(handle) } public keyFromKeyExchange(options: KeyFromKeyExchangeOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyFromKeyExchange(serializedOptions) + const handle = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyFromKeyExchange(serializedOptions))) return new LocalKeyHandle(handle) } public keyFromPublicBytes(options: KeyFromPublicBytesOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyFromPublicBytes(serializedOptions) + const handle = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyFromPublicBytes(serializedOptions))) return new LocalKeyHandle(handle) } public keyFromSecretBytes(options: KeyFromSecretBytesOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyFromSecretBytes(serializedOptions) + const handle = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyFromSecretBytes(serializedOptions))) return new LocalKeyHandle(handle) } public keyFromSeed(options: KeyFromSeedOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyFromSeed(serializedOptions) + const handle = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyFromSeed(serializedOptions))) return new LocalKeyHandle(handle) } public keyGenerate(options: KeyGenerateOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyGenerate(serializedOptions) + const handle = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyGenerate(serializedOptions))) - return new LocalKeyHandle(handle) + return new LocalKeyHandle(handleInvalidNullResponse(handle)) } public keyGetAlgorithm(options: KeyGetAlgorithmOptions): string { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.keyGetAlgorithm(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.keyGetAlgorithm(serializedOptions))) } public keyGetEphemeral(options: KeyGetEphemeralOptions): number { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.keyGetEphemeral(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.keyGetEphemeral(serializedOptions))) } public keyGetJwkPublic(options: KeyGetJwkPublicOptions): string { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.keyGetJwkPublic(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.keyGetJwkPublic(serializedOptions))) } public keyGetJwkSecret(options: KeyGetJwkSecretOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.keyGetJwkSecret(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyGetJwkSecret(serializedOptions))) return new Uint8Array(buf) } public keyGetJwkThumbprint(options: KeyGetJwkThumbprintOptions): string { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.keyGetJwkThumbprint(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.keyGetJwkThumbprint(serializedOptions))) } public keyGetPublicBytes(options: KeyGetPublicBytesOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.keyGetPublicBytes(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyGetPublicBytes(serializedOptions))) return new Uint8Array(buf) } public keyGetSecretBytes(options: KeyGetSecretBytesOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.keyGetSecretBytes(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyGetSecretBytes(serializedOptions))) return new Uint8Array(buf) } public keySignMessage(options: KeySignMessageOptions): Uint8Array { const serializedOptions = serializeArguments(options) - const buf = ariesAskarReactNative.keySignMessage(serializedOptions) + const buf = handleInvalidNullResponse(handleError(ariesAskarReactNative.keySignMessage(serializedOptions))) return new Uint8Array(buf) } public keyUnwrapKey(options: KeyUnwrapKeyOptions): LocalKeyHandle { const serializedOptions = serializeArguments(options) - const handle = ariesAskarReactNative.keyUnwrapKey(serializedOptions) + const handle = handleInvalidNullResponse(handleError(ariesAskarReactNative.keyUnwrapKey(serializedOptions))) return new LocalKeyHandle(handle) } public keyVerifySignature(options: KeyVerifySignatureOptions): boolean { const serializedOptions = serializeArguments(options) - const result = ariesAskarReactNative.keyVerifySignature(serializedOptions) + const result = handleError(ariesAskarReactNative.keyVerifySignature(serializedOptions)) return !!result } public keyWrapKey(options: KeyWrapKeyOptions): EncryptedBuffer { const serializedOptions = serializeArguments(options) - const { buffer, noncePos, tagPos } = ariesAskarReactNative.keyWrapKey(serializedOptions) + const ret = handleError(ariesAskarReactNative.keyWrapKey(serializedOptions)) + + const { buffer, noncePos, tagPos } = handleInvalidNullResponse(ret) return new EncryptedBuffer({ tagPos, noncePos, buffer: new Uint8Array(buffer) }) } public scanFree(options: ScanFreeOptions): void { const serializedOptions = serializeArguments(options) - ariesAskarReactNative.scanFree(serializedOptions) + + // null resopnse is expected as we're freeing the object + handleError(ariesAskarReactNative.scanFree(serializedOptions)) } - public async scanNext(options: ScanNextOptions): Promise { + public async scanNext(options: ScanNextOptions) { const serializedOptions = serializeArguments(options) const handle = await this.promisifyWithResponse((cb) => - ariesAskarReactNative.scanNext({ cb, ...serializedOptions }) + handleError(ariesAskarReactNative.scanNext({ cb, ...serializedOptions })) ) - return new EntryListHandle(handle) + return EntryListHandle.fromHandle(handle) } public async scanStart(options: ScanStartOptions): Promise { const { category, storeHandle, limit, offset, profile, tagFilter } = serializeArguments(options) - const handle = await this.promisifyWithResponse((cb) => - ariesAskarReactNative.scanStart({ - cb, - category, - storeHandle, - offset: offset || 0, - limit: limit || -1, - profile, - tagFilter, - }) + const handle = await this.promisifyWithResponse((cb) => + handleError( + ariesAskarReactNative.scanStart({ + cb, + category, + storeHandle, + offset: offset || 0, + limit: limit || -1, + profile, + tagFilter, + }) + ) ) - return new ScanHandle(handle) + return ScanHandle.fromHandle(handle) } public sessionClose(options: SessionCloseOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisify((cb) => ariesAskarReactNative.sessionClose({ cb, ...serializedOptions })) + return this.promisify((cb) => handleError(ariesAskarReactNative.sessionClose({ cb, ...serializedOptions }))) } - public sessionCount(options: SessionCountOptions): Promise { + public async sessionCount(options: SessionCountOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisifyWithResponse((cb) => - ariesAskarReactNative.sessionCount({ cb, ...serializedOptions }) + const response = await this.promisifyWithResponse((cb) => + handleError(ariesAskarReactNative.sessionCount({ cb, ...serializedOptions })) ) + + return handleInvalidNullResponse(response) } - public async sessionFetch(options: SessionFetchOptions): Promise { + public async sessionFetch(options: SessionFetchOptions) { const serializedOptions = serializeArguments(options) const handle = await this.promisifyWithResponse((cb) => - ariesAskarReactNative.sessionFetch({ cb, ...serializedOptions }) + handleError(ariesAskarReactNative.sessionFetch({ cb, ...serializedOptions })) ) - return new EntryListHandle(handle) + return EntryListHandle.fromHandle(handle) } - public async sessionFetchAll(options: SessionFetchAllOptions): Promise { + public async sessionFetchAll(options: SessionFetchAllOptions) { const { category, sessionHandle, forUpdate, limit, tagFilter } = serializeArguments(options) const handle = await this.promisifyWithResponse((cb) => - ariesAskarReactNative.sessionFetchAll({ cb, category, sessionHandle, forUpdate, limit: limit || -1, tagFilter }) + handleError( + ariesAskarReactNative.sessionFetchAll({ cb, category, sessionHandle, forUpdate, limit: limit || -1, tagFilter }) + ) ) - return new EntryListHandle(handle) + return EntryListHandle.fromHandle(handle) } - public async sessionFetchAllKeys(options: SessionFetchAllKeysOptions): Promise { + public async sessionFetchAllKeys(options: SessionFetchAllKeysOptions) { const { sessionHandle, algorithm, forUpdate, limit, thumbprint, tagFilter } = serializeArguments(options) const handle = await this.promisifyWithResponse((cb) => - ariesAskarReactNative.sessionFetchAllKeys({ - cb, - sessionHandle, - algorithm, - forUpdate: forUpdate || -1, - limit: limit || -1, - thumbprint, - tagFilter, - }) + handleError( + ariesAskarReactNative.sessionFetchAllKeys({ + cb, + sessionHandle, + algorithm, + forUpdate: forUpdate || -1, + limit: limit || -1, + thumbprint, + tagFilter, + }) + ) ) - return new KeyEntryListHandle(handle) + return KeyEntryListHandle.fromHandle(handle) } - public async sessionFetchKey(options: SessionFetchKeyOptions): Promise { + public async sessionFetchKey(options: SessionFetchKeyOptions) { const serializedOptions = serializeArguments(options) const handle = await this.promisifyWithResponse((cb) => - ariesAskarReactNative.sessionFetchKey({ cb, ...serializedOptions }) + handleError(ariesAskarReactNative.sessionFetchKey({ cb, ...serializedOptions })) ) - return new KeyEntryListHandle(handle) + return KeyEntryListHandle.fromHandle(handle) } public sessionInsertKey(options: SessionInsertKeyOptions): Promise { const { sessionHandle, name, localKeyHandle, expiryMs, metadata, tags } = serializeArguments(options) return this.promisify((cb) => - ariesAskarReactNative.sessionInsertKey({ - cb, - sessionHandle, - name, - localKeyHandle, - expiryMs: expiryMs || -1, - metadata, - tags, - }) + handleError( + ariesAskarReactNative.sessionInsertKey({ + cb, + sessionHandle, + name, + localKeyHandle, + expiryMs: expiryMs || -1, + metadata, + tags, + }) + ) ) } - public sessionRemoveAll(options: SessionRemoveAllOptions): Promise { + public async sessionRemoveAll(options: SessionRemoveAllOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisifyWithResponse((cb) => - ariesAskarReactNative.sessionRemoveAll({ cb, ...serializedOptions }) + const response = await this.promisifyWithResponse((cb) => + handleError(ariesAskarReactNative.sessionRemoveAll({ cb, ...serializedOptions })) ) + + return handleInvalidNullResponse(response) } public sessionRemoveKey(options: SessionRemoveKeyOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisify((cb) => ariesAskarReactNative.sessionRemoveKey({ cb, ...serializedOptions })) + return this.promisify((cb) => handleError(ariesAskarReactNative.sessionRemoveKey({ cb, ...serializedOptions }))) } public async sessionStart(options: SessionStartOptions): Promise { const serializedOptions = serializeArguments(options) - const handle = await this.promisifyWithResponse((cb) => - ariesAskarReactNative.sessionStart({ cb, ...serializedOptions }) + const handle = await this.promisifyWithResponse((cb) => + handleError(ariesAskarReactNative.sessionStart({ cb, ...serializedOptions })) ) - return new SessionHandle(handle) + return SessionHandle.fromHandle(handle) } public sessionUpdate(options: SessionUpdateOptions): Promise { const { category, name, operation, sessionHandle, expiryMs, tags, value } = serializeArguments(options) return this.promisify((cb) => - ariesAskarReactNative.sessionUpdate({ - cb, - category, - name, - operation, - sessionHandle, - expiryMs: expiryMs || -1, - tags, - value, - }) + handleError( + ariesAskarReactNative.sessionUpdate({ + cb, + category, + name, + operation, + sessionHandle, + expiryMs: expiryMs || -1, + tags, + value, + }) + ) ) } public sessionUpdateKey(options: SessionUpdateKeyOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisifyWithResponse((cb) => ariesAskarReactNative.sessionUpdateKey({ cb, ...serializedOptions })) + return this.promisify((cb) => handleError(ariesAskarReactNative.sessionUpdateKey({ cb, ...serializedOptions }))) } public storeClose(options: StoreCloseOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisify((cb) => ariesAskarReactNative.storeClose({ cb, ...serializedOptions })) + return this.promisify((cb) => handleError(ariesAskarReactNative.storeClose({ cb, ...serializedOptions }))) } - public storeCreateProfile(options: StoreCreateProfileOptions): Promise { + public async storeCreateProfile(options: StoreCreateProfileOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisifyWithResponse((cb) => - ariesAskarReactNative.storeCreateProfile({ cb, ...serializedOptions }) + const response = await this.promisifyWithResponse((cb) => + handleError(ariesAskarReactNative.storeCreateProfile({ cb, ...serializedOptions })) ) + + return handleInvalidNullResponse(response) } public storeGenerateRawKey(options: StoreGenerateRawKeyOptions): string { const serializedOptions = serializeArguments(options) - return ariesAskarReactNative.storeGenerateRawKey(serializedOptions) + return handleInvalidNullResponse(handleError(ariesAskarReactNative.storeGenerateRawKey(serializedOptions))) } - public storeGetProfileName(options: StoreGetProfileNameOptions): Promise { + public async storeGetProfileName(options: StoreGetProfileNameOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisifyWithResponse((cb) => - ariesAskarReactNative.storeGetProfileName({ cb, ...serializedOptions }) + const response = await this.promisifyWithResponse((cb) => + handleError(ariesAskarReactNative.storeGetProfileName({ cb, ...serializedOptions })) ) + + return handleInvalidNullResponse(response) } - public storeOpen(options: StoreOpenOptions): Promise { + public async storeOpen(options: StoreOpenOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisifyWithResponse((cb) => - ariesAskarReactNative.storeOpen({ cb, ...serializedOptions }) + const handle = await this.promisifyWithResponse((cb) => + handleError(ariesAskarReactNative.storeOpen({ cb, ...serializedOptions })) ) + + return StoreHandle.fromHandle(handle) } public async storeProvision(options: StoreProvisionOptions): Promise { const serializedOptions = serializeArguments(options) - const handle = await this.promisifyWithResponse((cb) => - ariesAskarReactNative.storeProvision({ cb, ...serializedOptions }) + const handle = await this.promisifyWithResponse((cb) => + handleError(ariesAskarReactNative.storeProvision({ cb, ...serializedOptions })) ) - return new StoreHandle(handle) + return StoreHandle.fromHandle(handle) } public storeRekey(options: StoreRekeyOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisify((cb) => ariesAskarReactNative.storeRekey({ cb, ...serializedOptions })) + return this.promisify((cb) => handleError(ariesAskarReactNative.storeRekey({ cb, ...serializedOptions }))) } - public storeRemove(options: StoreRemoveOptions): Promise { + public async storeRemove(options: StoreRemoveOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisifyWithResponse((cb) => ariesAskarReactNative.storeRemove({ cb, ...serializedOptions })) + const response = await this.promisifyWithResponse((cb) => + handleError(ariesAskarReactNative.storeRemove({ cb, ...serializedOptions })) + ) + + return handleInvalidNullResponse(response) } - public storeRemoveProfile(options: StoreRemoveProfileOptions): Promise { + public async storeRemoveProfile(options: StoreRemoveProfileOptions): Promise { const serializedOptions = serializeArguments(options) - return this.promisifyWithResponse((cb) => - ariesAskarReactNative.storeRemoveProfile({ cb, ...serializedOptions }) + const response = await this.promisifyWithResponse((cb) => + handleError(ariesAskarReactNative.storeRemoveProfile({ cb, ...serializedOptions })) ) + + return handleInvalidNullResponse(response) } } diff --git a/wrappers/javascript/aries-askar-react-native/src/library/NativeBindings.ts b/wrappers/javascript/aries-askar-react-native/src/library/NativeBindings.ts index 1388a646..b170b85a 100644 --- a/wrappers/javascript/aries-askar-react-native/src/library/NativeBindings.ts +++ b/wrappers/javascript/aries-askar-react-native/src/library/NativeBindings.ts @@ -1,21 +1,18 @@ -type LocalKeyHandle = string +import type { CallbackWithResponse, ReturnObject } from '../utils' -type CallbackWithResponse = (err: number, response: T) => void -type Callback = (err: number) => void +type LocalKeyHandle = string // TODO: convert all any types export interface NativeBindings { version(options: Record): string getCurrentError(options: Record): string - setConfig(options: { config: string }): null - clearCustomLogger(options: Record): void - entryListCount(options: { entryListHandle: string }): number - entryListFree(options: { entryListHandle: string }): void - entryListGetCategory(options: { entryListHandle: string; index: number }): string - entryListGetName(options: { entryListHandle: string; index: number }): string - entryListGetTags(options: { entryListHandle: string; index: number }): string - entryListGetValue(options: { entryListHandle: string; index: number }): ArrayBuffer + entryListCount(options: { entryListHandle: string }): ReturnObject + entryListFree(options: { entryListHandle: string }): ReturnObject + entryListGetCategory(options: { entryListHandle: string; index: number }): ReturnObject + entryListGetName(options: { entryListHandle: string; index: number }): ReturnObject + entryListGetTags(options: { entryListHandle: string; index: number }): ReturnObject + entryListGetValue(options: { entryListHandle: string; index: number }): ReturnObject keyAeadDecrypt(options: { localKeyHandle: string @@ -23,129 +20,134 @@ export interface NativeBindings { nonce: ArrayBuffer tag?: ArrayBuffer aad?: ArrayBuffer - }): ArrayBuffer + }): ReturnObject - keyAeadEncrypt(options: { localKeyHandle: string; message: ArrayBuffer; nonce?: ArrayBuffer; aad?: ArrayBuffer }): { + keyAeadEncrypt(options: { + localKeyHandle: string + message: ArrayBuffer + nonce?: ArrayBuffer + aad?: ArrayBuffer + }): ReturnObject<{ noncePos: number tagPos: number buffer: ArrayBuffer - } + }> - keyAeadGetPadding(options: { localKeyHandle: string; msgLen: number }): number + keyAeadGetPadding(options: { localKeyHandle: string; msgLen: number }): ReturnObject - keyAeadGetParams(options: { localKeyHandle: string }): { nonceLength: number; tagLength: number } + keyAeadGetParams(options: { localKeyHandle: string }): ReturnObject<{ nonceLength: number; tagLength: number }> - keyAeadRandomNonce(options: any): ArrayBuffer + keyAeadRandomNonce(options: any): ReturnObject - keyConvert(options: any): LocalKeyHandle + keyConvert(options: any): ReturnObject - keyCryptoBox(options: any): ArrayBuffer + keyCryptoBox(options: any): ReturnObject - keyCryptoBoxOpen(options: any): ArrayBuffer + keyCryptoBoxOpen(options: any): ReturnObject - keyCryptoBoxRandomNonce(options: Record): ArrayBuffer + keyCryptoBoxRandomNonce(options: Record): ReturnObject - keyCryptoBoxSeal(options: any): ArrayBuffer + keyCryptoBoxSeal(options: any): ReturnObject - keyCryptoBoxSealOpen(options: any): ArrayBuffer + keyCryptoBoxSealOpen(options: any): ReturnObject - keyDeriveEcdh1pu(options: any): LocalKeyHandle + keyDeriveEcdh1pu(options: any): ReturnObject - keyDeriveEcdhEs(options: any): LocalKeyHandle + keyDeriveEcdhEs(options: any): ReturnObject - keyEntryListCount(options: any): number + keyEntryListCount(options: any): ReturnObject - keyEntryListFree(options: any): void + keyEntryListFree(options: any): ReturnObject - keyEntryListGetAlgorithm(options: any): string + keyEntryListGetAlgorithm(options: any): ReturnObject - keyEntryListGetMetadata(options: any): string + keyEntryListGetMetadata(options: any): ReturnObject - keyEntryListGetName(options: any): string + keyEntryListGetName(options: any): ReturnObject - keyEntryListGetTags(options: any): string + keyEntryListGetTags(options: any): ReturnObject - keyEntryListLoadLocal(options: any): LocalKeyHandle + keyEntryListLoadLocal(options: any): ReturnObject - keyFree(options: any): void + keyFree(options: any): ReturnObject - keyFromJwk(options: any): LocalKeyHandle + keyFromJwk(options: any): ReturnObject - keyFromKeyExchange(options: any): LocalKeyHandle + keyFromKeyExchange(options: any): ReturnObject - keyFromPublicBytes(options: any): LocalKeyHandle + keyFromPublicBytes(options: any): ReturnObject - keyFromSecretBytes(options: any): LocalKeyHandle + keyFromSecretBytes(options: any): ReturnObject - keyFromSeed(options: any): LocalKeyHandle + keyFromSeed(options: any): ReturnObject - keyGenerate(options: any): LocalKeyHandle + keyGenerate(options: any): ReturnObject - keyGetAlgorithm(options: any): string + keyGetAlgorithm(options: any): ReturnObject - keyGetEphemeral(options: any): number + keyGetEphemeral(options: any): ReturnObject - keyGetJwkPublic(options: any): string + keyGetJwkPublic(options: any): ReturnObject - keyGetJwkSecret(options: any): ArrayBuffer + keyGetJwkSecret(options: any): ReturnObject - keyGetJwkThumbprint(options: any): string + keyGetJwkThumbprint(options: any): ReturnObject - keyGetPublicBytes(options: any): ArrayBuffer + keyGetPublicBytes(options: any): ReturnObject - keyGetSecretBytes(options: any): ArrayBuffer + keyGetSecretBytes(options: any): ReturnObject - keySignMessage(options: any): ArrayBuffer + keySignMessage(options: any): ReturnObject - keyUnwrapKey(options: any): LocalKeyHandle + keyUnwrapKey(options: any): ReturnObject - keyVerifySignature(options: any): number + keyVerifySignature(options: any): ReturnObject - keyWrapKey(options: any): { buffer: ArrayBuffer; tagPos: number; noncePos: number } + keyWrapKey(options: any): ReturnObject<{ buffer: ArrayBuffer; tagPos: number; noncePos: number }> - scanFree(options: any): void + scanFree(options: any): ReturnObject - scanNext(options: any): void + scanNext(options: any): ReturnObject - scanStart(options: any): number + scanStart(options: any): ReturnObject - sessionClose(options: any): void + sessionClose(options: any): ReturnObject - sessionCount(options: any): void + sessionCount(options: any): ReturnObject - sessionFetch(options: any): void + sessionFetch(options: any): ReturnObject - sessionFetchAll(options: any): void + sessionFetchAll(options: any): ReturnObject - sessionFetchAllKeys(options: any): void + sessionFetchAllKeys(options: any): ReturnObject - sessionFetchKey(options: any): void + sessionFetchKey(options: any): ReturnObject - sessionInsertKey(options: any): void + sessionInsertKey(options: any): ReturnObject - sessionRemoveAll(options: any): void + sessionRemoveAll(options: any): ReturnObject - sessionRemoveKey(options: any): void + sessionRemoveKey(options: any): ReturnObject - sessionStart(options: any): void + sessionStart(options: any): ReturnObject - sessionUpdate(options: any): void + sessionUpdate(options: any): ReturnObject - sessionUpdateKey(options: any): void + sessionUpdateKey(options: any): ReturnObject - setCustomLogger(options: any): void + setCustomLogger(options: any): ReturnObject - setDefaultLogger(options: any): void + setDefaultLogger(options: any): ReturnObject - setMaxLogLevel(options: any): void + setMaxLogLevel(options: any): ReturnObject - storeClose(options: any): void + storeClose(options: any): ReturnObject - storeCreateProfile(options: any): void + storeCreateProfile(options: any): ReturnObject - storeGenerateRawKey(options: { seed?: ArrayBuffer }): string + storeGenerateRawKey(options: { seed?: ArrayBuffer }): ReturnObject - storeGetProfileName(options: any): void + storeGetProfileName(options: any): ReturnObject storeOpen(options: { specUri: string @@ -153,13 +155,13 @@ export interface NativeBindings { passKey?: string profile?: string cb: CallbackWithResponse - }): void + }): ReturnObject - storeProvision(options: any): void + storeProvision(options: any): ReturnObject - storeRekey(options: any): void + storeRekey(options: any): ReturnObject - storeRemove(options: any): void + storeRemove(options: any): ReturnObject - storeRemoveProfile(options: any): void + storeRemoveProfile(options: any): ReturnObject } diff --git a/wrappers/javascript/aries-askar-react-native/src/utils/handleError.ts b/wrappers/javascript/aries-askar-react-native/src/utils/handleError.ts new file mode 100644 index 00000000..16ae57b3 --- /dev/null +++ b/wrappers/javascript/aries-askar-react-native/src/utils/handleError.ts @@ -0,0 +1,12 @@ +import type { ReturnObject } from './serialize' +import type { AriesAskarErrorObject } from '@hyperledger/aries-askar-shared' + +import { ariesAskar, AriesAskarError } from '@hyperledger/aries-askar-shared' + +export const handleError = ({ errorCode, value }: ReturnObject): T => { + if (errorCode !== 0) { + throw new AriesAskarError(JSON.parse(ariesAskar.getCurrentError()) as AriesAskarErrorObject) + } + + return value as T +} diff --git a/wrappers/javascript/aries-askar-react-native/src/utils/index.ts b/wrappers/javascript/aries-askar-react-native/src/utils/index.ts index f6c820ef..e63d8513 100644 --- a/wrappers/javascript/aries-askar-react-native/src/utils/index.ts +++ b/wrappers/javascript/aries-askar-react-native/src/utils/index.ts @@ -1 +1,2 @@ export * from './serialize' +export * from './handleError' diff --git a/wrappers/javascript/aries-askar-react-native/src/utils/serialize.ts b/wrappers/javascript/aries-askar-react-native/src/utils/serialize.ts index 76384e28..6c221e28 100644 --- a/wrappers/javascript/aries-askar-react-native/src/utils/serialize.ts +++ b/wrappers/javascript/aries-askar-react-native/src/utils/serialize.ts @@ -1,7 +1,12 @@ import { ArcHandle, Jwk, ScanHandle, SessionHandle, StoreHandle, Key } from '@hyperledger/aries-askar-shared' -export type Callback = (err: number) => void -export type CallbackWithResponse = (err: number, response: string) => void +export type ReturnObject = { + errorCode: number + value?: null | T +} + +export type Callback = (o: ReturnObject) => void +export type CallbackWithResponse = (o: ReturnObject) => void type Argument = | Record diff --git a/wrappers/javascript/aries-askar-shared/src/ariesAskar/AriesAskar.ts b/wrappers/javascript/aries-askar-shared/src/ariesAskar/AriesAskar.ts index e4999bfb..1c23bffc 100644 --- a/wrappers/javascript/aries-askar-shared/src/ariesAskar/AriesAskar.ts +++ b/wrappers/javascript/aries-askar-shared/src/ariesAskar/AriesAskar.ts @@ -234,7 +234,7 @@ export type AriesAskar = { entryListFree(options: EntryListFreeOptions): void entryListGetCategory(options: EntryListGetCategoryOptions): string entryListGetName(options: EntryListGetNameOptions): string - entryListGetTags(options: EntryListGetTagsOptions): string + entryListGetTags(options: EntryListGetTagsOptions): string | null entryListGetValue(options: EntryListGetValueOptions): Uint8Array keyAeadDecrypt(options: KeyAeadDecryptOptions): Uint8Array @@ -253,9 +253,9 @@ export type AriesAskar = { keyEntryListCount(options: KeyEntryListCountOptions): number keyEntryListFree(options: KeyEntryListFreeOptions): void keyEntryListGetAlgorithm(options: KeyEntryListGetAlgorithmOptions): string - keyEntryListGetMetadata(options: KeyEntryListGetMetadataOptions): string + keyEntryListGetMetadata(options: KeyEntryListGetMetadataOptions): string | null keyEntryListGetName(options: KeyEntryListGetNameOptions): string - keyEntryListGetTags(options: KeyEntryListGetTagsOptions): string + keyEntryListGetTags(options: KeyEntryListGetTagsOptions): string | null keyEntryListLoadLocal(options: KeyEntryListLoadLocalOptions): LocalKeyHandle keyFree(options: KeyFreeOptions): void keyFromJwk(options: KeyFromJwkOptions): LocalKeyHandle @@ -277,15 +277,15 @@ export type AriesAskar = { keyWrapKey(options: KeyWrapKeyOptions): EncryptedBuffer scanFree(options: ScanFreeOptions): void - scanNext(options: ScanNextOptions): Promise + scanNext(options: ScanNextOptions): Promise scanStart(options: ScanStartOptions): Promise sessionClose(options: SessionCloseOptions): Promise sessionCount(options: SessionCountOptions): Promise - sessionFetch(options: SessionFetchOptions): Promise - sessionFetchAll(options: SessionFetchAllOptions): Promise - sessionFetchAllKeys(options: SessionFetchAllKeysOptions): Promise - sessionFetchKey(options: SessionFetchKeyOptions): Promise + sessionFetch(options: SessionFetchOptions): Promise + sessionFetchAll(options: SessionFetchAllOptions): Promise + sessionFetchAllKeys(options: SessionFetchAllKeysOptions): Promise + sessionFetchKey(options: SessionFetchKeyOptions): Promise sessionInsertKey(options: SessionInsertKeyOptions): Promise sessionRemoveAll(options: SessionRemoveAllOptions): Promise sessionRemoveKey(options: SessionRemoveKeyOptions): Promise diff --git a/wrappers/javascript/aries-askar-shared/src/crypto/handles.ts b/wrappers/javascript/aries-askar-shared/src/crypto/handles.ts index 3121f177..0d853e3a 100644 --- a/wrappers/javascript/aries-askar-shared/src/crypto/handles.ts +++ b/wrappers/javascript/aries-askar-shared/src/crypto/handles.ts @@ -1,6 +1,8 @@ import { ariesAskar } from '../ariesAskar' import { AriesAskarError } from '../error' +type ArcHandleType = Uint8Array | string | null + export class ArcHandle { public handle: Uint8Array | string @@ -12,6 +14,10 @@ export class ArcHandle { } this.handle = handle } + + public static fromHandle(handle: ArcHandleType) { + return fromPointerHandle(this, handle) + } } export class StoreHandle { @@ -24,6 +30,10 @@ export class StoreHandle { public async close() { await ariesAskar.storeClose({ storeHandle: this }) } + + public static fromHandle(handle: number | null) { + return fromSequenceHandle(this, handle) + } } export class ScanHandle { @@ -36,6 +46,10 @@ export class ScanHandle { public free() { ariesAskar.scanFree({ scanHandle: this }) } + + public static fromHandle(handle: number | null) { + return fromSequenceHandle(this, handle) + } } export class SessionHandle { @@ -48,6 +62,10 @@ export class SessionHandle { public async close(commit: boolean) { await ariesAskar.sessionClose({ commit, sessionHandle: this }) } + + public static fromHandle(handle: number | null) { + return fromSequenceHandle(this, handle) + } } export class EntryListHandle extends ArcHandle { @@ -70,6 +88,10 @@ export class EntryListHandle extends ArcHandle { public free() { ariesAskar.entryListFree({ entryListHandle: this }) } + + public static fromHandle(handle: ArcHandleType) { + return fromPointerHandle(this, handle) + } } export class KeyEntryListHandle extends ArcHandle { @@ -96,10 +118,40 @@ export class KeyEntryListHandle extends ArcHandle { public free() { ariesAskar.keyEntryListFree({ keyEntryListHandle: this }) } + + public static fromHandle(handle: ArcHandleType) { + return fromPointerHandle(this, handle) + } } export class LocalKeyHandle extends ArcHandle { public free() { ariesAskar.keyFree({ keyHandle: this }) } + + public static fromHandle(handle: ArcHandleType) { + return fromPointerHandle(this, handle) + } +} + +/** + * Instantiate an handle class based on a received handle. If the handle has a value + * of null, the handle class won't be instantiated but rather null will be returned. + */ +function fromPointerHandle( + HandleClass: HC, + handle: H +): H extends null ? null : InstanceType { + return (handle ? (new HandleClass(handle) as InstanceType) : null) as H extends null ? null : InstanceType +} + +function fromSequenceHandle< + HC extends typeof StoreHandle | typeof ScanHandle | typeof SessionHandle, + H extends number | null +>(HandleClass: HC, handle: H): InstanceType { + if (handle === null) { + throw AriesAskarError.customError({ message: 'Invalid handle' }) + } + + return new HandleClass(handle) as InstanceType } diff --git a/wrappers/javascript/aries-askar-shared/src/error.ts b/wrappers/javascript/aries-askar-shared/src/error.ts index 0ed35f29..efb042f1 100644 --- a/wrappers/javascript/aries-askar-shared/src/error.ts +++ b/wrappers/javascript/aries-askar-shared/src/error.ts @@ -18,3 +18,11 @@ export class AriesAskarError extends Error { return new AriesAskarError({ message, code: 100 }) } } + +export function handleInvalidNullResponse(response: T): Exclude { + if (response === null) { + throw AriesAskarError.customError({ message: 'Invalid response. Expected value but received null pointer' }) + } + + return response as Exclude +} diff --git a/wrappers/javascript/aries-askar-shared/src/store/Entry.ts b/wrappers/javascript/aries-askar-shared/src/store/Entry.ts index 3633ded7..cf05c7fd 100644 --- a/wrappers/javascript/aries-askar-shared/src/store/Entry.ts +++ b/wrappers/javascript/aries-askar-shared/src/store/Entry.ts @@ -9,19 +9,19 @@ export type EntryObject = { export class Entry { private _list: EntryListHandle - private _position: number + private _pos: number public constructor({ list, position }: { list: EntryListHandle; position: number }) { this._list = list - this._position = position + this._pos = position } public get category() { - return this._list.getCategory(this._position) + return this._list.getCategory(this._pos) } public get name() { - return this._list.getName(this._position) + return this._list.getName(this._pos) } public get value(): string { @@ -34,12 +34,14 @@ export class Entry { } private get rawValue() { - // why does this not work return - return this._list.getValue(this._position) + return this._list.getValue(this._pos) } public get tags() { - return JSON.parse(this._list.getTags(this._position)) as Record + const tags = this._list.getTags(this._pos) + + if (!tags) return {} + return JSON.parse(tags) as Record } public toJson(shouldParseValueToJson = false): EntryObject { diff --git a/wrappers/javascript/aries-askar-shared/src/store/EntryList.ts b/wrappers/javascript/aries-askar-shared/src/store/EntryList.ts index 2dfd0ca2..6b484c2c 100644 --- a/wrappers/javascript/aries-askar-shared/src/store/EntryList.ts +++ b/wrappers/javascript/aries-askar-shared/src/store/EntryList.ts @@ -39,9 +39,9 @@ export class EntryList { } } - public toArray(): Array { + public toArray(valuesAreJson?: boolean): Array { const list: Array = [] - this.forEach((entry) => list.push(entry.toJson())) + this.forEach((entry) => list.push(entry.toJson(valuesAreJson))) return list } } diff --git a/wrappers/javascript/aries-askar-shared/src/store/KeyEntry.ts b/wrappers/javascript/aries-askar-shared/src/store/KeyEntry.ts index a46afcc9..8d90f9bf 100644 --- a/wrappers/javascript/aries-askar-shared/src/store/KeyEntry.ts +++ b/wrappers/javascript/aries-askar-shared/src/store/KeyEntry.ts @@ -5,7 +5,7 @@ import { Key } from '../crypto' export type KeyEntryObject = { algorithm: string name: string - metadata: string + metadata: string | null tags: Record key: Key } @@ -28,11 +28,16 @@ export class KeyEntry { } public get metadata() { - return this._list.getMetadata(this._pos) + const metadata = this._list.getMetadata(this._pos) + + return metadata } public get tags() { - return JSON.parse(this._list.getTags(this._pos)) as Record + const tags = this._list.getTags(this._pos) + + if (!tags) return {} + return JSON.parse(tags) as Record } public get key() { diff --git a/wrappers/javascript/aries-askar-shared/src/store/Scan.ts b/wrappers/javascript/aries-askar-shared/src/store/Scan.ts index a8860137..3fb98776 100644 --- a/wrappers/javascript/aries-askar-shared/src/store/Scan.ts +++ b/wrappers/javascript/aries-askar-shared/src/store/Scan.ts @@ -64,8 +64,10 @@ export class Scan { // Loop while limit not reached (or no limit specified) while (!this.limit || recordCount < this.limit) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this._listHandle = await ariesAskar.scanNext({ scanHandle: this._handle! }) + const listHandle = await ariesAskar.scanNext({ scanHandle: this._handle! }) + if (!listHandle) break + this._listHandle = listHandle const list = new EntryList({ handle: this._listHandle }) recordCount = recordCount + list.length diff --git a/wrappers/javascript/aries-askar-shared/src/store/Session.ts b/wrappers/javascript/aries-askar-shared/src/store/Session.ts index b3268b9d..f4dcbd79 100644 --- a/wrappers/javascript/aries-askar-shared/src/store/Session.ts +++ b/wrappers/javascript/aries-askar-shared/src/store/Session.ts @@ -35,7 +35,7 @@ export class Session { category, name, forUpdate = false, - isJson = false, + isJson, }: { category: string name: string @@ -45,7 +45,7 @@ export class Session { if (!this.handle) throw AriesAskarError.customError({ message: 'Cannot fetch from a closed session' }) const handle = await ariesAskar.sessionFetch({ forUpdate, name, category, sessionHandle: this.handle }) - if (!handle) return undefined + if (!handle) return null const entry = new Entry({ list: handle, position: 0 }) const entryObject = entry.toJson(isJson) @@ -60,11 +60,13 @@ export class Session { forUpdate = false, limit, tagFilter, + isJson, }: { category: string tagFilter?: Record limit?: number forUpdate?: boolean + isJson?: boolean }) { if (!this.handle) throw AriesAskarError.customError({ message: 'Cannot fetch all from a closed session' }) const handle = await ariesAskar.sessionFetchAll({ @@ -74,8 +76,10 @@ export class Session { sessionHandle: this.handle, category, }) + if (!handle) return [] + const entryList = new EntryList({ handle }) - const entryObjects = entryList.toArray() + const entryObjects = entryList.toArray(isJson) entryList.handle.free() @@ -196,10 +200,12 @@ export class Session { public async fetchKey({ name, forUpdate = false }: { name: string; forUpdate?: boolean }) { if (!this.handle) throw AriesAskarError.customError({ message: 'Cannot fetch a key with a closed session' }) + const handle = await ariesAskar.sessionFetchKey({ forUpdate, name, sessionHandle: this.handle }) + if (!handle) return null + const keyEntryList = new KeyEntryList({ handle }) const keyEntryObject = keyEntryList.getEntryByIndex(0).toJson() - keyEntryList.handle.free() return keyEntryObject @@ -227,6 +233,7 @@ export class Session { algorithm, sessionHandle: this.handle, }) + if (!handle) return [] const keyEntryList = new KeyEntryList({ handle }) const keyEntryObjects = keyEntryList.toArray()