Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/wet-comics-love.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@openwallet-foundation/askar-react-native": patch
"@openwallet-foundation/askar-nodejs": patch
"@openwallet-foundation/askar-shared": patch
---

fix: wrap the askar registration with a `NativeAskar` class that exposes two static members: a `.instance` getter and `register` method.

Previously when you did not import the native askar library on the first line (or above all logic that uses Askar) the reference to Askar would be undefined. (i.e. askar-shared is imported before askar-react-native or askar-nodejs)

The `registerAskar` method and `askar` property are kept for backwards compatibility, but these are still prone to the same error. `registerAskar` integrated with the new `NativeAskar` class, and so all usages within the shared library, as well as the nodejs and react-native wrappers will be fixed. We recommend to update to the new `NativeAskar` class for all other usages.
2 changes: 1 addition & 1 deletion packages/askar-nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
},
"dependencies": {
"@openwallet-foundation/askar-shared": "workspace:*",
"koffi": "^2.9.0"
"koffi": "^2.14.1"
},
"devDependencies": {
"@types/node": "catalog:",
Expand Down
4 changes: 2 additions & 2 deletions packages/askar-nodejs/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { registerAskar } from '@openwallet-foundation/askar-shared'
import { NativeAskar } from '@openwallet-foundation/askar-shared'
import { NodeJSAskar } from './NodeJSAskar'

export const askarNodeJS = new NodeJSAskar()
registerAskar({ askar: askarNodeJS })
NativeAskar.register(askarNodeJS)

export * from '@openwallet-foundation/askar-shared'
2 changes: 1 addition & 1 deletion packages/askar-nodejs/src/library/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const getLibrary = () => {
path.join(p, `${extensions[platform].prefix ?? ''}${LIBNAME}${extensions[platform].extension}`)
)

// Gaurd so we quit if there is no valid path for the library
// Guard so we quit if there is no valid path for the library
if (!libraries.some((libraryPath) => doesPathExist(libraryPath)))
throw new Error(`Could not find ${LIBNAME} with these paths: ${libraries.join(' ')}`)

Expand Down
4 changes: 2 additions & 2 deletions packages/askar-react-native/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { registerAskar } from '@openwallet-foundation/askar-shared'
import { NativeAskar } from '@openwallet-foundation/askar-shared'
import { NativeModules } from 'react-native'
import type { NativeBindings } from './NativeBindings'

Expand All @@ -17,4 +17,4 @@ if (!_askar) {

declare let _askar: NativeBindings

registerAskar({ askar: new ReactNativeAskar(_askar) })
NativeAskar.register(new ReactNativeAskar(_askar))
28 changes: 27 additions & 1 deletion packages/askar-shared/src/askar/register.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
import { AskarError } from '../error'
import type { Askar } from './Askar'

/**
* @deprecated use `NativeAskar.instance` instead
*/
export let askar: Askar

export class NativeAskar {
static #nativeAskar: Askar | undefined

public static get instance(): Askar {
if (!NativeAskar.#nativeAskar)
throw AskarError.customError({
message:
"Native askar has not been registered yet. Make sure to import '@openwallet-foundation/askar-nodejs' or '@openwallet-foundation/askar-react-native', or call 'NativeAskar.register' with a custom implementation.",
})

return NativeAskar.#nativeAskar
}

public static register(nativeAskar: Askar) {
askar = nativeAskar
NativeAskar.#nativeAskar = nativeAskar
}
}

/**
* @deprecated use `NativeAskar.register` instead
*/
export const registerAskar = (options: { askar: Askar }) => {
askar = options.askar
NativeAskar.register(options.askar)
}
4 changes: 2 additions & 2 deletions packages/askar-shared/src/crypto/Argon2.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { askar } from '../askar'
import { NativeAskar } from '../askar'

export enum Argon2Parameters {
Moderate = 0,
Expand All @@ -7,6 +7,6 @@ export enum Argon2Parameters {

export class Argon2 {
public static derivePassword(parameters: Argon2Parameters, password: Uint8Array, salt: Uint8Array): Uint8Array {
return askar.argon2DerivePassword({ parameters, password, salt })
return NativeAskar.instance.argon2DerivePassword({ parameters, password, salt })
}
}
12 changes: 6 additions & 6 deletions packages/askar-shared/src/crypto/CryptoBox.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { askar } from '../askar'
import { NativeAskar } from '../askar'
import type { Key } from './Key'

export class CryptoBox {
public static randomNonce() {
return askar.keyCryptoBoxRandomNonce()
return NativeAskar.instance.keyCryptoBoxRandomNonce()
}

public static cryptoBox({
Expand All @@ -17,7 +17,7 @@ export class CryptoBox {
message: Uint8Array
nonce: Uint8Array
}) {
return askar.keyCryptoBox({ nonce, message, senderKey, recipientKey })
return NativeAskar.instance.keyCryptoBox({ nonce, message, senderKey, recipientKey })
}

public static open({
Expand All @@ -31,14 +31,14 @@ export class CryptoBox {
message: Uint8Array
nonce: Uint8Array
}) {
return askar.keyCryptoBoxOpen({ nonce, message, senderKey, recipientKey })
return NativeAskar.instance.keyCryptoBoxOpen({ nonce, message, senderKey, recipientKey })
}

public static seal({ recipientKey, message }: { recipientKey: Key; message: Uint8Array }) {
return askar.keyCryptoBoxSeal({ message, localKeyHandle: recipientKey.handle })
return NativeAskar.instance.keyCryptoBoxSeal({ message, localKeyHandle: recipientKey.handle })
}

public static sealOpen({ recipientKey, ciphertext }: { recipientKey: Key; ciphertext: Uint8Array }) {
return askar.keyCryptoBoxSealOpen({ ciphertext, localKeyHandle: recipientKey.handle })
return NativeAskar.instance.keyCryptoBoxSealOpen({ ciphertext, localKeyHandle: recipientKey.handle })
}
}
4 changes: 2 additions & 2 deletions packages/askar-shared/src/crypto/Ecdh1PU.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { askar } from '../askar'
import { NativeAskar } from '../askar'
import type { KeyAlgorithm } from '../enums'
import { Key } from './Key'

Expand Down Expand Up @@ -29,7 +29,7 @@ export class Ecdh1PU {
ccTag?: Uint8Array
}): Key {
return new Key(
askar.keyDeriveEcdh1pu({
NativeAskar.instance.keyDeriveEcdh1pu({
algId: this.algId,
receive,
apv: this.apv,
Expand Down
4 changes: 2 additions & 2 deletions packages/askar-shared/src/crypto/EcdhEs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { askar } from '../askar'
import { askar, NativeAskar } from '../askar'
import type { KeyAlgorithm } from '../enums'

import { Jwk } from './Jwk'
Expand Down Expand Up @@ -27,7 +27,7 @@ export class EcdhEs {
receive: boolean
}): Key {
return new Key(
askar.keyDeriveEcdhEs({
NativeAskar.instance.keyDeriveEcdhEs({
algId: this.algId,
receive,
apv: this.apv,
Expand Down
46 changes: 23 additions & 23 deletions packages/askar-shared/src/crypto/Key.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Buffer } from 'buffer'
import { askar } from '../askar'
import { askar, NativeAskar } from '../askar'
import type { KeyAlgorithm, KeyBackend, SignatureAlgorithm } from '../enums'
import { KeyMethod, keyAlgorithmFromString } from '../enums'
import type { LocalKeyHandle } from './handles'
Expand All @@ -14,7 +14,7 @@ export class Key {
}

public static generate(algorithm: KeyAlgorithm, keyBackend?: KeyBackend, ephemeral = false) {
return new Key(askar.keyGenerate({ algorithm, keyBackend, ephemeral }))
return new Key(NativeAskar.instance.keyGenerate({ algorithm, keyBackend, ephemeral }))
}

public static fromSeed({
Expand All @@ -26,28 +26,28 @@ export class Key {
seed: Uint8Array
method?: KeyMethod
}) {
return new Key(askar.keyFromSeed({ algorithm, method, seed }))
return new Key(NativeAskar.instance.keyFromSeed({ algorithm, method, seed }))
}

public static fromSecretBytes(options: { algorithm: KeyAlgorithm; secretKey: Uint8Array }) {
return new Key(askar.keyFromSecretBytes(options))
return new Key(NativeAskar.instance.keyFromSecretBytes(options))
}

public static fromPublicBytes(options: { algorithm: KeyAlgorithm; publicKey: Uint8Array }) {
return new Key(askar.keyFromPublicBytes(options))
return new Key(NativeAskar.instance.keyFromPublicBytes(options))
}

public static fromJwk(options: { jwk: Jwk }) {
return new Key(askar.keyFromJwk(options))
return new Key(NativeAskar.instance.keyFromJwk(options))
}

public convertkey(options: { algorithm: KeyAlgorithm }) {
return new Key(askar.keyConvert({ localKeyHandle: this.handle, ...options }))
return new Key(NativeAskar.instance.keyConvert({ localKeyHandle: this.handle, ...options }))
}

public keyFromKeyExchange({ algorithm, publicKey }: { algorithm: KeyAlgorithm; publicKey: Key }) {
return new Key(
askar.keyFromKeyExchange({
NativeAskar.instance.keyFromKeyExchange({
skHandle: this.handle,
pkHandle: publicKey.handle,
algorithm,
Expand All @@ -60,90 +60,90 @@ export class Key {
}

public get algorithm() {
const alg = askar.keyGetAlgorithm({ localKeyHandle: this.handle })
const alg = NativeAskar.instance.keyGetAlgorithm({ localKeyHandle: this.handle })
return keyAlgorithmFromString(alg)
}

public get ephemeral() {
return Boolean(askar.keyGetEphemeral({ localKeyHandle: this.handle }))
return Boolean(NativeAskar.instance.keyGetEphemeral({ localKeyHandle: this.handle }))
}

public get publicBytes() {
return askar.keyGetPublicBytes({ localKeyHandle: this.handle })
return NativeAskar.instance.keyGetPublicBytes({ localKeyHandle: this.handle })
}

public get secretBytes() {
return askar.keyGetSecretBytes({ localKeyHandle: this.handle })
return NativeAskar.instance.keyGetSecretBytes({ localKeyHandle: this.handle })
}

public get jwkPublic(): Jwk {
return Jwk.fromString(
askar.keyGetJwkPublic({
NativeAskar.instance.keyGetJwkPublic({
localKeyHandle: this.handle,
algorithm: this.algorithm,
})
)
}

public get jwkSecret() {
const secretBytes = askar.keyGetJwkSecret({
const secretBytes = NativeAskar.instance.keyGetJwkSecret({
localKeyHandle: this.handle,
})
return Jwk.fromString(Buffer.from(secretBytes).toString())
}

public get jwkThumbprint() {
return askar.keyGetJwkThumbprint({
return NativeAskar.instance.keyGetJwkThumbprint({
localKeyHandle: this.handle,
algorithm: this.algorithm,
})
}

public get aeadParams() {
return askar.keyAeadGetParams({ localKeyHandle: this.handle })
return NativeAskar.instance.keyAeadGetParams({ localKeyHandle: this.handle })
}

public get aeadRandomNonce() {
return askar.keyAeadRandomNonce({ localKeyHandle: this.handle })
return NativeAskar.instance.keyAeadRandomNonce({ localKeyHandle: this.handle })
}

public aeadEncrypt(options: { message: Uint8Array; nonce?: Uint8Array; aad?: Uint8Array }) {
return askar.keyAeadEncrypt({
return NativeAskar.instance.keyAeadEncrypt({
localKeyHandle: this.handle,
...options,
})
}

public aeadDecrypt(options: { ciphertext: Uint8Array; nonce: Uint8Array; tag?: Uint8Array; aad?: Uint8Array }) {
return askar.keyAeadDecrypt({
return NativeAskar.instance.keyAeadDecrypt({
localKeyHandle: this.handle,
...options,
})
}

public signMessage(options: { message: Uint8Array; sigType?: SignatureAlgorithm }) {
return askar.keySignMessage({
return NativeAskar.instance.keySignMessage({
localKeyHandle: this.handle,
...options,
})
}

public verifySignature(options: { message: Uint8Array; signature: Uint8Array; sigType?: SignatureAlgorithm }) {
return askar.keyVerifySignature({
return NativeAskar.instance.keyVerifySignature({
localKeyHandle: this.handle,
...options,
})
}

public wrapKey({ other, nonce }: { other: Key; nonce?: Uint8Array }) {
return askar.keyWrapKey({
return NativeAskar.instance.keyWrapKey({
localKeyHandle: this.handle,
other: other.handle,
nonce,
})
}

public unwrapKey(options: { algorithm: KeyAlgorithm; tag?: Uint8Array; ciphertext: Uint8Array; nonce?: Uint8Array }) {
return new Key(askar.keyUnwrapKey({ localKeyHandle: this.handle, ...options }))
return new Key(NativeAskar.instance.keyUnwrapKey({ localKeyHandle: this.handle, ...options }))
}
}
Loading