From 7b6f26b2caf33fcacd6802763d40855af0b01cfd Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Mon, 9 Sep 2024 23:45:24 -0400 Subject: [PATCH 01/20] feat: add pbkdf2, test ncrypto --- .../src/keys/index.ts | 99 ++++++++ .../{zzz/ts => src}/pbkdf2.ts | 80 +++--- .../react-native-quick-crypto/src/random.ts | 4 +- .../src/specs/keyObjectHandle.nitro.ts | 23 ++ .../pbkdf2.ts => src/specs/pbkdf2.nitro.ts} | 4 +- .../src/specs/random.nitro.ts | 2 +- .../src/utils/conversion.ts | 84 ++++++- .../src/utils/errors.ts | 15 ++ .../src/utils/hashnames.ts | 96 +++++++ .../src/utils/index.ts | 9 +- .../src/utils/types.ts | 177 ++++++++++++- .../zzz/ts/NativeQuickCrypto/webcrypto.ts | 30 +-- .../react-native-quick-crypto/zzz/ts/keys.ts | 234 ------------------ .../react-native-quick-crypto/zzz/ts/utils.ts | 103 -------- 14 files changed, 535 insertions(+), 425 deletions(-) create mode 100644 packages/react-native-quick-crypto/src/keys/index.ts rename packages/react-native-quick-crypto/{zzz/ts => src}/pbkdf2.ts (74%) create mode 100644 packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts rename packages/react-native-quick-crypto/{zzz/ts/NativeQuickCrypto/pbkdf2.ts => src/specs/pbkdf2.nitro.ts} (68%) create mode 100644 packages/react-native-quick-crypto/src/utils/errors.ts create mode 100644 packages/react-native-quick-crypto/src/utils/hashnames.ts diff --git a/packages/react-native-quick-crypto/src/keys/index.ts b/packages/react-native-quick-crypto/src/keys/index.ts new file mode 100644 index 00000000..a3bf1ff1 --- /dev/null +++ b/packages/react-native-quick-crypto/src/keys/index.ts @@ -0,0 +1,99 @@ +import type { KeyObjectHandle } from "../specs/keyObjectHandle.nitro"; +import type { EncodingOptions, KeyUsage, SubtleAlgorithm } from "../utils"; + +export class CryptoKey { + keyObject: KeyObject; + keyAlgorithm: SubtleAlgorithm; + keyUsages: KeyUsage[]; + keyExtractable: boolean; + + constructor( + keyObject: KeyObject, + keyAlgorithm: SubtleAlgorithm, + keyUsages: KeyUsage[], + keyExtractable: boolean + ) { + this.keyObject = keyObject; + this.keyAlgorithm = keyAlgorithm; + this.keyUsages = keyUsages; + this.keyExtractable = keyExtractable; + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + inspect(_depth: number, _options: unknown): unknown { + throw new Error('CryptoKey.inspect is not implemented'); + // if (depth < 0) return this; + + // const opts = { + // ...options, + // depth: options.depth == null ? null : options.depth - 1, + // }; + + // return `CryptoKey ${inspect( + // { + // type: this.type, + // extractable: this.extractable, + // algorithm: this.algorithm, + // usages: this.usages, + // }, + // opts + // )}`; + } + + get type() { + // if (!(this instanceof CryptoKey)) throw new Error('Invalid CryptoKey'); + return this.keyObject.type; + } + + get extractable() { + return this.keyExtractable; + } + + get algorithm() { + return this.keyAlgorithm; + } + + get usages() { + return this.keyUsages; + } +} + +class KeyObject { + handle: KeyObjectHandle; + type: 'public' | 'secret' | 'private' | 'unknown' = 'unknown'; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + export(_options?: EncodingOptions): ArrayBuffer { + return new ArrayBuffer(0); + } + + constructor(type: string, handle: KeyObjectHandle) { + if (type !== 'secret' && type !== 'public' && type !== 'private') + throw new Error(`invalid KeyObject type: ${type}`); + this.handle = handle; + this.type = type; + } + + // get type(): string { + // return this.type; + // } + + // static from(key) { + // if (!isCryptoKey(key)) + // throw new ERR_INVALID_ARG_TYPE('key', 'CryptoKey', key); + // return key[kKeyObject]; + // } + + // equals(otherKeyObject) { + // if (!isKeyObject(otherKeyObject)) { + // throw new ERR_INVALID_ARG_TYPE( + // 'otherKeyObject', + // 'KeyObject', + // otherKeyObject + // ); + // } + + // return ( + // otherKeyObject.type === this.type && + // this[kHandle].equals(otherKeyObject[kHandle]) + // ); + // } +} diff --git a/packages/react-native-quick-crypto/zzz/ts/pbkdf2.ts b/packages/react-native-quick-crypto/src/pbkdf2.ts similarity index 74% rename from packages/react-native-quick-crypto/zzz/ts/pbkdf2.ts rename to packages/react-native-quick-crypto/src/pbkdf2.ts index a8f6df6a..5df7a9bf 100644 --- a/packages/react-native-quick-crypto/zzz/ts/pbkdf2.ts +++ b/packages/react-native-quick-crypto/src/pbkdf2.ts @@ -1,15 +1,19 @@ -import { NativeQuickCrypto } from './NativeQuickCrypto/NativeQuickCrypto'; import { Buffer } from '@craftzdog/react-native-buffer'; +import { NitroModules } from 'react-native-nitro-modules'; +import type { + BinaryLike, +} from './utils'; import { - type BinaryLike, + HashContext, binaryLikeToArrayBuffer, - lazyDOMException, bufferLikeToArrayBuffer, - normalizeHashName, - HashContext, + lazyDOMException, + normalizeHashName } from './utils'; -import type { CryptoKey, HashAlgorithm, SubtleAlgorithm } from './keys'; +import type { HashAlgorithm, SubtleAlgorithm } from './utils'; +import type { Pbkdf2 } from './specs/pbkdf2.nitro'; import { promisify } from 'util'; +import type { CryptoKey } from './keys'; const WRONG_PASS = 'Password must be a string, a Buffer, a typed array or a DataView'; @@ -19,66 +23,47 @@ type Password = BinaryLike; type Salt = BinaryLike; type Pbkdf2Callback = (err: Error | null, derivedKey?: Buffer) => void; +// to use native bits in sub-functions, use getNative(). don't call it at top-level! +let native: Pbkdf2; +function getNative(): Pbkdf2 { + if (native == null) { + // lazy-load the Nitro HybridObject + native = NitroModules.createHybridObject('Pbkdf2'); + } + return native; +} + function sanitizeInput(input: BinaryLike, errorMsg: string): ArrayBuffer { try { return binaryLikeToArrayBuffer(input); - } catch (e: any) { - throw errorMsg; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_e: unknown) { + throw new Error(errorMsg); } } -const nativePbkdf2 = NativeQuickCrypto.pbkdf2; - export function pbkdf2( password: Password, salt: Salt, iterations: number, keylen: number, - digest: HashAlgorithm, - callback: Pbkdf2Callback -): void; -export function pbkdf2( - password: Password, - salt: Salt, - iterations: number, - keylen: number, - callback: Pbkdf2Callback -): void; -export function pbkdf2( - password: Password, - salt: Salt, - iterations: number, - keylen: number, - arg0?: unknown, - arg1?: unknown + digest: string, + callback: Pbkdf2Callback, ): void { - let digest: HashAlgorithm = 'SHA-1'; - let callback: undefined | Pbkdf2Callback; - if (typeof arg0 === 'string') { - digest = arg0 as HashAlgorithm; - if (typeof arg1 === 'function') { - callback = arg1 as Pbkdf2Callback; - } - } else { - if (typeof arg0 === 'function') { - callback = arg0 as Pbkdf2Callback; - } - } - if (callback === undefined) { + if (callback === undefined || typeof callback !== 'function') { throw new Error('No callback provided to pbkdf2'); } - const sanitizedPassword = sanitizeInput(password, WRONG_PASS); const sanitizedSalt = sanitizeInput(salt, WRONG_SALT); const normalizedDigest = normalizeHashName(digest, HashContext.Node); - nativePbkdf2 - .pbkdf2( + getNative(); + native.pbkdf2( sanitizedPassword, sanitizedSalt, iterations, keylen, - normalizedDigest + normalizedDigest, ) .then( (res: ArrayBuffer) => { @@ -86,7 +71,7 @@ export function pbkdf2( }, (e: Error) => { callback!(e); - } + }, ); } @@ -101,7 +86,8 @@ export function pbkdf2Sync( const sanitizedSalt = sanitizeInput(salt, WRONG_SALT); const algo = digest ? normalizeHashName(digest, HashContext.Node) : 'sha1'; - let result: ArrayBuffer = nativePbkdf2.pbkdf2Sync( + getNative(); + const result: ArrayBuffer = native.pbkdf2Sync( sanitizedPassword, sanitizedSalt, iterations, @@ -152,7 +138,7 @@ export async function pbkdf2DeriveBits( const sanitizedPassword = sanitizeInput(raw, WRONG_PASS); const sanitizedSalt = sanitizeInput(salt, WRONG_SALT); - let result: Buffer | undefined = await pbkdf2Promise( + const result: Buffer | undefined = await pbkdf2Promise( sanitizedPassword, sanitizedSalt, iterations, diff --git a/packages/react-native-quick-crypto/src/random.ts b/packages/react-native-quick-crypto/src/random.ts index 67d45a67..c524de6f 100644 --- a/packages/react-native-quick-crypto/src/random.ts +++ b/packages/react-native-quick-crypto/src/random.ts @@ -1,6 +1,6 @@ import { Buffer } from '@craftzdog/react-native-buffer'; -import type { ArrayBufferView, RandomCallback } from './utils/types'; -import { abvToArrayBuffer } from './utils/conversion'; +import type { ArrayBufferView, RandomCallback } from './utils'; +import { abvToArrayBuffer } from './utils'; import { NitroModules } from 'react-native-nitro-modules'; import type { Random } from './specs/random.nitro'; diff --git a/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts b/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts new file mode 100644 index 00000000..aca5eea6 --- /dev/null +++ b/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts @@ -0,0 +1,23 @@ +import { type HybridObject } from 'react-native-nitro-modules'; +import type { AsymmetricKeyType, BinaryLike, JWK, KeyDetail, KeyEncoding, KeyType, KFormatType, NamedCurve } from '../utils'; + +export interface KeyObjectHandle extends HybridObject<{ ios: 'c++'; android: 'c++' }> { + export( + format?: KFormatType, + type?: KeyEncoding, + cipher?: string, + passphrase?: BinaryLike, + ): ArrayBuffer; + exportJwk(key: JWK, handleRsaPss: boolean): JWK; + getAsymmetricKeyType(): AsymmetricKeyType; + init( + keyType: KeyType, + key: string | ArrayBuffer, + format?: KFormatType, + type?: KeyEncoding, + passphrase?: BinaryLike, + ): boolean; + initECRaw(curveName: string, keyData: ArrayBuffer): boolean; + initJwk(keyData: JWK, namedCurve?: NamedCurve): KeyType | undefined; + keyDetail(): KeyDetail; +}; \ No newline at end of file diff --git a/packages/react-native-quick-crypto/zzz/ts/NativeQuickCrypto/pbkdf2.ts b/packages/react-native-quick-crypto/src/specs/pbkdf2.nitro.ts similarity index 68% rename from packages/react-native-quick-crypto/zzz/ts/NativeQuickCrypto/pbkdf2.ts rename to packages/react-native-quick-crypto/src/specs/pbkdf2.nitro.ts index ebadb489..270ff2be 100644 --- a/packages/react-native-quick-crypto/zzz/ts/NativeQuickCrypto/pbkdf2.ts +++ b/packages/react-native-quick-crypto/src/specs/pbkdf2.nitro.ts @@ -1,4 +1,6 @@ -export type Pbkdf2Object = { +import { type HybridObject } from 'react-native-nitro-modules'; + +export interface Pbkdf2 extends HybridObject<{ ios: 'c++'; android: 'c++' }> { pbkdf2: ( password: ArrayBuffer, salt: ArrayBuffer, diff --git a/packages/react-native-quick-crypto/src/specs/random.nitro.ts b/packages/react-native-quick-crypto/src/specs/random.nitro.ts index 5896a8db..fc63c3f9 100644 --- a/packages/react-native-quick-crypto/src/specs/random.nitro.ts +++ b/packages/react-native-quick-crypto/src/specs/random.nitro.ts @@ -11,4 +11,4 @@ export interface Random extends HybridObject<{ ios: 'c++'; android: 'c++' }> { offset: number, size: number ): ArrayBuffer; -} +}; diff --git a/packages/react-native-quick-crypto/src/utils/conversion.ts b/packages/react-native-quick-crypto/src/utils/conversion.ts index dea3efe3..03dad89f 100644 --- a/packages/react-native-quick-crypto/src/utils/conversion.ts +++ b/packages/react-native-quick-crypto/src/utils/conversion.ts @@ -1,5 +1,6 @@ import { Buffer } from '@craftzdog/react-native-buffer'; -import type { ArrayBufferView } from './types'; +import { Buffer as SBuffer } from 'safe-buffer'; +import type { ArrayBufferView, BinaryLikeNode, BufferLike } from './types'; export const abvToArrayBuffer = (buffer: ArrayBufferView) => { if (Buffer.isBuffer(buffer)) { @@ -11,6 +12,87 @@ export const abvToArrayBuffer = (buffer: ArrayBufferView) => { return buffer; }; +export function toArrayBuffer(buf: Buffer | SBuffer): ArrayBuffer { + if (Buffer.isBuffer(buf) && buf?.buffer?.slice) { + return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); + } + const ab = new ArrayBuffer(buf.length); + const view = new Uint8Array(ab); + for (let i = 0; i < buf.length; ++i) { + view[i] = SBuffer.isBuffer(buf) ? buf.readUInt8(i) : buf[i]!; + } + return ab; +} + +export function bufferLikeToArrayBuffer(buf: BufferLike): ArrayBuffer { + if (Buffer.isBuffer(buf)) { + return buf.buffer; + } + if (SBuffer.isBuffer(buf)) { + return toArrayBuffer(buf); + } + if (ArrayBuffer.isView(buf)) { + return buf.buffer; + } + return buf; +} + +export function binaryLikeToArrayBuffer( + input: BinaryLikeNode, // CipherKey adds compat with node types + encoding: string = 'utf-8', +): ArrayBuffer { + // string + if (typeof input === 'string') { + if (encoding === 'buffer') { + throw new Error( + 'Cannot create a buffer from a string with a buffer encoding', + ); + } + + const buffer = Buffer.from(input, encoding); + + return buffer.buffer.slice( + buffer.byteOffset, + buffer.byteOffset + buffer.byteLength, + ); + } + + // Buffer + if (Buffer.isBuffer(input)) { + return toArrayBuffer(input); + } + + // ArrayBufferView + // TODO add further binary types to BinaryLike, UInt8Array and so for have this array as property + if (ArrayBuffer.isView(input)) { + return input.buffer; + } + + // ArrayBuffer + if (input instanceof ArrayBuffer) { + return input; + } + + // if (!(input instanceof ArrayBuffer)) { + // try { + // // this is a strange fallback case and input is unknown at this point + // const buffer = Buffer.from(input as unknown as string); + // return buffer.buffer.slice( + // buffer.byteOffset, + // buffer.byteOffset + buffer.byteLength + // ); + // } catch(e: unknown) { + // console.log('throwing 1'); + // const err = e as Error; + // throw new Error(err.message); + // } + // } + + // TODO: handle if input is KeyObject? + + throw new Error('input could not be converted to ArrayBuffer'); +} + export function ab2str(buf: ArrayBuffer, encoding: string = 'hex') { return Buffer.from(buf).toString(encoding); } diff --git a/packages/react-native-quick-crypto/src/utils/errors.ts b/packages/react-native-quick-crypto/src/utils/errors.ts new file mode 100644 index 00000000..abf9c6f8 --- /dev/null +++ b/packages/react-native-quick-crypto/src/utils/errors.ts @@ -0,0 +1,15 @@ +type DOMName = + | string + | { + name: string; + cause: unknown; + }; + +export function lazyDOMException(message: string, domName: DOMName): Error { + let cause = ''; + if (typeof domName !== 'string') { + cause = `\nCaused by: ${domName.cause}`; + } + + return new Error(`[${domName}]: ${message}${cause}`); +} diff --git a/packages/react-native-quick-crypto/src/utils/hashnames.ts b/packages/react-native-quick-crypto/src/utils/hashnames.ts new file mode 100644 index 00000000..94ff028f --- /dev/null +++ b/packages/react-native-quick-crypto/src/utils/hashnames.ts @@ -0,0 +1,96 @@ +import type { HashAlgorithm } from '.'; + +export enum HashContext { + Node, + WebCrypto, + JwkRsa, + JwkRsaPss, + JwkRsaOaep, + JwkHmac, +} + +// WebCrypto and JWK use a bunch of different names for the +// standard set of SHA-* digest algorithms... which is ... fun. +// Here we provide a utility for mapping between them in order +// make it easier in the code. + +type HashNames = { + [key: string]: { [key in HashContext as string]: string }; +}; + +const kHashNames: HashNames = { + sha1: { + [HashContext.Node]: 'sha1', + [HashContext.WebCrypto]: 'SHA-1', + [HashContext.JwkRsa]: 'RS1', + [HashContext.JwkRsaPss]: 'PS1', + [HashContext.JwkRsaOaep]: 'RSA-OAEP', + [HashContext.JwkHmac]: 'HS1', + }, + sha224: { + [HashContext.Node]: 'sha224', + [HashContext.WebCrypto]: 'SHA-224', + [HashContext.JwkRsa]: 'RS224', + [HashContext.JwkRsaPss]: 'PS224', + [HashContext.JwkRsaOaep]: 'RSA-OAEP-224', + [HashContext.JwkHmac]: 'HS224', + }, + sha256: { + [HashContext.Node]: 'sha256', + [HashContext.WebCrypto]: 'SHA-256', + [HashContext.JwkRsa]: 'RS256', + [HashContext.JwkRsaPss]: 'PS256', + [HashContext.JwkRsaOaep]: 'RSA-OAEP-256', + [HashContext.JwkHmac]: 'HS256', + }, + sha384: { + [HashContext.Node]: 'sha384', + [HashContext.WebCrypto]: 'SHA-384', + [HashContext.JwkRsa]: 'RS384', + [HashContext.JwkRsaPss]: 'PS384', + [HashContext.JwkRsaOaep]: 'RSA-OAEP-384', + [HashContext.JwkHmac]: 'HS384', + }, + sha512: { + [HashContext.Node]: 'sha512', + [HashContext.WebCrypto]: 'SHA-512', + [HashContext.JwkRsa]: 'RS512', + [HashContext.JwkRsaPss]: 'PS512', + [HashContext.JwkRsaOaep]: 'RSA-OAEP-512', + [HashContext.JwkHmac]: 'HS512', + }, + ripemd160: { + [HashContext.Node]: 'ripemd160', + [HashContext.WebCrypto]: 'RIPEMD-160', + }, +}; + +{ + // Index the aliases + const keys: string[] = Object.keys(kHashNames); + for (let n: number = 0; n < keys.length; n++) { + const contexts: string[] = Object.keys(kHashNames[keys[n]!]!); + for (let i: number = 0; i < contexts.length; i++) { + const alias: string = kHashNames[keys[n]!]![contexts[i]!]!.toLowerCase(); + if (kHashNames[alias] === undefined) + kHashNames[alias] = kHashNames[keys[n]!]!; + } + } +} + +export function normalizeHashName( + algo: string | HashAlgorithm | undefined, + context: HashContext = HashContext.Node, +): HashAlgorithm { + if (typeof algo !== 'undefined') { + const normAlgo = algo.toString().toLowerCase(); + try { + const alias = kHashNames[normAlgo]![context] as HashAlgorithm; + if (alias) return alias; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_e) { + // ignore + } + } + throw new Error(`Invalid Hash Algorithm: ${algo}`); +} \ No newline at end of file diff --git a/packages/react-native-quick-crypto/src/utils/index.ts b/packages/react-native-quick-crypto/src/utils/index.ts index 3b237b52..9a43de0e 100644 --- a/packages/react-native-quick-crypto/src/utils/index.ts +++ b/packages/react-native-quick-crypto/src/utils/index.ts @@ -1,6 +1,5 @@ -import { ab2str, abvToArrayBuffer } from "./conversion"; +export * from './conversion'; +export * from './errors'; +export * from './hashnames'; +export * from './types'; -export const utils = { - ab2str, - abvToArrayBuffer, -}; diff --git a/packages/react-native-quick-crypto/src/utils/types.ts b/packages/react-native-quick-crypto/src/utils/types.ts index 4ba8f5b1..c0f1bbe4 100644 --- a/packages/react-native-quick-crypto/src/utils/types.ts +++ b/packages/react-native-quick-crypto/src/utils/types.ts @@ -1,3 +1,7 @@ +import { Buffer } from '@craftzdog/react-native-buffer'; +import { Buffer as SBuffer } from 'safe-buffer'; +import { type CipherKey } from 'crypto'; // @types/node + export type ArrayBufferView = TypedArray | DataView | ArrayBufferLike | Buffer; export type TypedArray = @@ -11,5 +15,174 @@ export type TypedArray = | Float32Array | Float64Array; - export type RandomCallback = (err: Error | null, value: T) => void; - \ No newline at end of file +export type RandomCallback = (err: Error | null, value: T) => void; + +export type BufferLike = ArrayBuffer | Buffer | SBuffer | ArrayBufferView; + +export type BinaryLike = + | string + | ArrayBuffer + | Buffer + | SBuffer + | TypedArray + | DataView; + +export type BinaryLikeNode = CipherKey | BinaryLike; + +export type DigestAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512'; + +export type HashAlgorithm = DigestAlgorithm | 'SHA-224' | 'RIPEMD-160'; + +export type RSAKeyPairAlgorithm = 'RSASSA-PKCS1-v1_5' | 'RSA-PSS' | 'RSA-OAEP'; + +export type ECKeyPairAlgorithm = 'ECDSA' | 'ECDH'; + +export type CFRGKeyPairAlgorithm = 'Ed25519' | 'Ed448' | 'X25519' | 'X448'; + +export type KeyPairAlgorithm = + | RSAKeyPairAlgorithm + | ECKeyPairAlgorithm + | CFRGKeyPairAlgorithm; + +export type AESAlgorithm = 'AES-CTR' | 'AES-CBC' | 'AES-GCM' | 'AES-KW'; + +export type SecretKeyAlgorithm = 'HMAC' | AESAlgorithm; + +export type SignVerifyAlgorithm = + | 'RSASSA-PKCS1-v1_5' + | 'RSA-PSS' + | 'ECDSA' + | 'HMAC' + | 'Ed25519' + | 'Ed448'; + +export type DeriveBitsAlgorithm = + | 'PBKDF2' + | 'HKDF' + | 'ECDH' + | 'X25519' + | 'X448'; + +export type EncryptDecryptAlgorithm = + | 'RSA-OAEP' + | 'AES-CTR' + | 'AES-CBC' + | 'AES-GCM'; + +export type AnyAlgorithm = + | DigestAlgorithm + | HashAlgorithm + | KeyPairAlgorithm + | SecretKeyAlgorithm + | SignVerifyAlgorithm + | DeriveBitsAlgorithm + | EncryptDecryptAlgorithm + | AESAlgorithm + | 'PBKDF2' + | 'HKDF' + | 'unknown'; + +export type NamedCurve = 'P-256' | 'P-384' | 'P-521'; + +export type SubtleAlgorithm = { + name: AnyAlgorithm; + salt?: string; + iterations?: number; + hash?: HashAlgorithm; + namedCurve?: NamedCurve; + length?: number; + modulusLength?: number; + publicExponent?: number | Uint8Array; +}; + +export type KeyUsage = + | 'encrypt' + | 'decrypt' + | 'sign' + | 'verify' + | 'deriveKey' + | 'deriveBits' + | 'wrapKey' + | 'unwrapKey'; + +// On node this value is defined on the native side, for now I'm just creating it here in JS +// TODO(osp) move this into native side to make sure they always match +export enum KFormatType { + kKeyFormatDER, + kKeyFormatPEM, + kKeyFormatJWK, +} + +// Same as KFormatType, this enum needs to be defined on the native side +export enum KeyType { + Secret, + Public, + Private, +} + +export enum KeyEncoding { + kKeyEncodingPKCS1, + kKeyEncodingPKCS8, + kKeyEncodingSPKI, + kKeyEncodingSEC1, +} + +export type AsymmetricKeyType = 'rsa' | 'rsa-pss' | 'dsa' | 'ec' | undefined; + +export type JWK = { + 'kty'?: 'AES' | 'RSA' | 'EC' | 'oct'; + 'use'?: 'sig' | 'enc'; + 'key_ops'?: KeyUsage[]; + 'alg'?: string; // TODO: enumerate these (RFC-7517) + 'crv'?: string; + 'kid'?: string; + 'x5u'?: string; + 'x5c'?: string[]; + 'x5t'?: string; + 'x5t#256'?: string; + 'n'?: string; + 'e'?: string; + 'd'?: string; + 'p'?: string; + 'q'?: string; + 'x'?: string; + 'y'?: string; + 'k'?: string; + 'dp'?: string; + 'dq'?: string; + 'qi'?: string; + 'ext'?: boolean; +}; + +export type KTypePrivate = 'pkcs1' | 'pkcs8' | 'sec1'; +export type KTypePublic = 'pkcs1' | 'spki'; +export type KType = KTypePrivate | KTypePublic; + +export type KFormat = 'der' | 'pem' | 'jwk'; + +export type DSAEncoding = 'der' | 'ieee-p1363'; + +export type EncodingOptions = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + key?: any; + type?: KType; + encoding?: string; + dsaEncoding?: DSAEncoding; + format?: KFormat; + padding?: number; + cipher?: string; + passphrase?: BinaryLike; + saltLength?: number; + oaepHash?: string; + oaepLabel?: BinaryLike; +}; + +export type KeyDetail = { + length?: number; + publicExponent?: number; + modulusLength?: number; + hashAlgorithm?: string; + mgf1HashAlgorithm?: string; + saltLength?: number; + namedCurve?: string; +}; diff --git a/packages/react-native-quick-crypto/zzz/ts/NativeQuickCrypto/webcrypto.ts b/packages/react-native-quick-crypto/zzz/ts/NativeQuickCrypto/webcrypto.ts index 26a63170..501cf9b1 100644 --- a/packages/react-native-quick-crypto/zzz/ts/NativeQuickCrypto/webcrypto.ts +++ b/packages/react-native-quick-crypto/zzz/ts/NativeQuickCrypto/webcrypto.ts @@ -16,15 +16,6 @@ import type { import type { KeyVariant } from './Cipher'; import type { RSACipher } from './rsa'; -type KeyDetail = { - length?: number; - publicExponent?: number; - modulusLength?: number; - hashAlgorithm?: string; - mgf1HashAlgorithm?: string; - saltLength?: number; - namedCurve?: string; -}; type ECExportKey = ( format: KWebCryptoKeyFormat, @@ -37,26 +28,7 @@ type RSAExportKey = ( variant: KeyVariant ) => ArrayBuffer; -export type KeyObjectHandle = { - export( - format?: KFormatType, - type?: KeyEncoding, - cipher?: string, - passphrase?: ArrayBuffer - ): ArrayBuffer; - exportJwk(key: JWK, handleRsaPss: boolean): JWK; - getAsymmetricKeyType(): AsymmetricKeyType; - init( - keyType: KeyType, - key: any, - format?: KFormatType, - type?: KeyEncoding, - passphrase?: string | ArrayBuffer - ): boolean; - initECRaw(curveName: string, keyData: ArrayBuffer): boolean; - initJwk(keyData: JWK, namedCurve?: NamedCurve): KeyType | undefined; - keyDetail(): KeyDetail; -}; + type CreateKeyObjectHandle = () => KeyObjectHandle; diff --git a/packages/react-native-quick-crypto/zzz/ts/keys.ts b/packages/react-native-quick-crypto/zzz/ts/keys.ts index 8f803974..4098c7db 100644 --- a/packages/react-native-quick-crypto/zzz/ts/keys.ts +++ b/packages/react-native-quick-crypto/zzz/ts/keys.ts @@ -15,60 +15,13 @@ export const kNamedCurveAliases = { 'P-521': 'secp521r1', } as const; -export type NamedCurve = 'P-256' | 'P-384' | 'P-521'; - export type ImportFormat = 'raw' | 'pkcs8' | 'spki' | 'jwk'; -export type AnyAlgorithm = - | HashAlgorithm - | KeyPairAlgorithm - | SecretKeyAlgorithm - | SignVerifyAlgorithm - | DeriveBitsAlgorithm - | EncryptDecryptAlgorithm - | 'PBKDF2' - | 'HKDF'; - -export type HashAlgorithm = - | 'SHA-1' - | 'SHA-224' - | 'SHA-256' - | 'SHA-384' - | 'SHA-512' - | 'RIPEMD-160'; - -export type DigestAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512'; - export type KeyPairType = 'rsa' | 'rsa-pss' | 'ec'; -export type RSAKeyPairAlgorithm = 'RSASSA-PKCS1-v1_5' | 'RSA-PSS' | 'RSA-OAEP'; -export type ECKeyPairAlgorithm = 'ECDSA' | 'ECDH'; -export type CFRGKeyPairAlgorithm = 'Ed25519' | 'Ed448' | 'X25519' | 'X448'; -export type AESAlgorithm = 'AES-CTR' | 'AES-CBC' | 'AES-GCM' | 'AES-KW'; - -export type KeyPairAlgorithm = - | RSAKeyPairAlgorithm - | ECKeyPairAlgorithm - | CFRGKeyPairAlgorithm; -export type SecretKeyAlgorithm = 'HMAC' | AESAlgorithm; export type SecretKeyType = 'hmac' | 'aes'; -export type SignVerifyAlgorithm = - | 'RSASSA-PKCS1-v1_5' - | 'RSA-PSS' - | 'ECDSA' - | 'HMAC' - | 'Ed25519' - | 'Ed448'; - -export type DeriveBitsAlgorithm = - | 'PBKDF2' - | 'HKDF' - | 'ECDH' - | 'X25519' - | 'X448'; - export type RsaOaepParams = { name: 'RSA-OAEP'; label?: BufferLike; @@ -112,53 +65,8 @@ export type EncryptDecryptParams = | AesGcmParams | RsaOaepParams; -export type EncryptDecryptAlgorithm = - | 'RSA-OAEP' - | 'AES-CTR' - | 'AES-CBC' - | 'AES-GCM'; - -export type SubtleAlgorithm = { - name: AnyAlgorithm; - salt?: string; - iterations?: number; - hash?: HashAlgorithm; - namedCurve?: NamedCurve; - length?: number; - modulusLength?: number; - publicExponent?: any; -}; -export type KeyUsage = - | 'encrypt' - | 'decrypt' - | 'sign' - | 'verify' - | 'deriveKey' - | 'deriveBits' - | 'wrapKey' - | 'unwrapKey'; - -// On node this value is defined on the native side, for now I'm just creating it here in JS -// TODO(osp) move this into native side to make sure they always match -export enum KFormatType { - kKeyFormatDER, - kKeyFormatPEM, - kKeyFormatJWK, -} -export type KFormat = 'der' | 'pem' | 'jwk'; - -// Same as KFormatType, this enum needs to be defined on the native side -export enum KeyType { - Secret, - Public, - Private, -} - -export type KTypePrivate = 'pkcs1' | 'pkcs8' | 'sec1'; -export type KTypePublic = 'pkcs1' | 'spki'; -export type KType = KTypePrivate | KTypePublic; // Same as KFormatType, this enum needs to be defined on the native side export enum KWebCryptoKeyFormat { @@ -181,54 +89,6 @@ enum KeyInputContext { kCreatePrivate, } -export enum KeyEncoding { - kKeyEncodingPKCS1, - kKeyEncodingPKCS8, - kKeyEncodingSPKI, - kKeyEncodingSEC1, -} - -export type DSAEncoding = 'der' | 'ieee-p1363'; - -export type EncodingOptions = { - key?: any; - type?: KType; - encoding?: string; - dsaEncoding?: DSAEncoding; - format?: KFormat; - padding?: number; - cipher?: string; - passphrase?: string | ArrayBuffer; - saltLength?: number; -}; - -export type AsymmetricKeyType = 'rsa' | 'rsa-pss' | 'dsa' | 'ec' | undefined; - -export type JWK = { - 'kty'?: 'AES' | 'RSA' | 'EC' | 'oct'; - 'use'?: 'sig' | 'enc'; - 'key_ops'?: KeyUsage[]; - 'alg'?: string; // TODO: enumerate these (RFC-7517) - 'crv'?: string; - 'kid'?: string; - 'x5u'?: string; - 'x5c'?: string[]; - 'x5t'?: string; - 'x5t#256'?: string; - 'n'?: string; - 'e'?: string; - 'd'?: string; - 'p'?: string; - 'q'?: string; - 'x'?: string; - 'y'?: string; - 'k'?: string; - 'dp'?: string; - 'dq'?: string; - 'qi'?: string; - 'ext'?: boolean; -}; - const encodingNames = { [KeyEncoding.kKeyEncodingPKCS1]: 'pkcs1', [KeyEncoding.kKeyEncodingPKCS8]: 'pkcs8', @@ -580,101 +440,7 @@ export const createPrivateKey = ( // return obj != null && obj.keyType !== undefined; // }; -export class CryptoKey { - keyObject: KeyObject; - keyAlgorithm: SubtleAlgorithm; - keyUsages: KeyUsage[]; - keyExtractable: boolean; - - constructor( - keyObject: KeyObject, - keyAlgorithm: SubtleAlgorithm, - keyUsages: KeyUsage[], - keyExtractable: boolean - ) { - this.keyObject = keyObject; - this.keyAlgorithm = keyAlgorithm; - this.keyUsages = keyUsages; - this.keyExtractable = keyExtractable; - } - inspect(_depth: number, _options: any): any { - throw new Error('CryptoKey.inspect is not implemented'); - // if (depth < 0) return this; - - // const opts = { - // ...options, - // depth: options.depth == null ? null : options.depth - 1, - // }; - - // return `CryptoKey ${inspect( - // { - // type: this.type, - // extractable: this.extractable, - // algorithm: this.algorithm, - // usages: this.usages, - // }, - // opts - // )}`; - } - - get type() { - // if (!(this instanceof CryptoKey)) throw new Error('Invalid CryptoKey'); - return this.keyObject.type; - } - - get extractable() { - return this.keyExtractable; - } - - get algorithm() { - return this.keyAlgorithm; - } - - get usages() { - return this.keyUsages; - } -} - -class KeyObject { - handle: KeyObjectHandle; - type: 'public' | 'secret' | 'private' | 'unknown' = 'unknown'; - export(_options?: EncodingOptions): ArrayBuffer { - return new ArrayBuffer(0); - } - - constructor(type: string, handle: KeyObjectHandle) { - if (type !== 'secret' && type !== 'public' && type !== 'private') - throw new Error(`invalid KeyObject type: ${type}`); - this.handle = handle; - this.type = type; - } - - // get type(): string { - // return this.type; - // } - - // static from(key) { - // if (!isCryptoKey(key)) - // throw new ERR_INVALID_ARG_TYPE('key', 'CryptoKey', key); - // return key[kKeyObject]; - // } - - // equals(otherKeyObject) { - // if (!isKeyObject(otherKeyObject)) { - // throw new ERR_INVALID_ARG_TYPE( - // 'otherKeyObject', - // 'KeyObject', - // otherKeyObject - // ); - // } - - // return ( - // otherKeyObject.type === this.type && - // this[kHandle].equals(otherKeyObject[kHandle]) - // ); - // } -} export class SecretKeyObject extends KeyObject { constructor(handle: KeyObjectHandle) { diff --git a/packages/react-native-quick-crypto/zzz/ts/utils.ts b/packages/react-native-quick-crypto/zzz/ts/utils.ts index 7b154513..4d3ab859 100644 --- a/packages/react-native-quick-crypto/zzz/ts/utils.ts +++ b/packages/react-native-quick-crypto/zzz/ts/utils.ts @@ -1,4 +1,3 @@ -import { Buffer } from '@craftzdog/react-native-buffer'; import type { AnyAlgorithm, DeriveBitsAlgorithm, @@ -11,11 +10,6 @@ import type { SignVerifyAlgorithm, SubtleAlgorithm, } from './keys'; -import { type CipherKey } from 'crypto'; // @types/node - -export type BufferLike = ArrayBuffer | Buffer | ArrayBufferView; -export type BinaryLike = string | ArrayBuffer | Buffer | TypedArray; -export type BinaryLikeNode = CipherKey | BinaryLike; export type BinaryToTextEncoding = 'base64' | 'base64url' | 'hex' | 'binary'; export type CharacterEncoding = 'utf8' | 'utf-8' | 'utf16le' | 'latin1'; @@ -28,24 +22,6 @@ export type Encoding = // TODO(osp) should buffer be part of the Encoding type? export type CipherEncoding = Encoding | 'buffer'; -export type TypedArray = - | Uint8Array - | Uint8ClampedArray - | Uint16Array - | Uint32Array - | Int8Array - | Int16Array - | Int32Array - | Float32Array - | Float64Array; - -type DOMName = - | string - | { - name: string; - cause: any; - }; - // Mimics node behavior for default global encoding let defaultEncoding: CipherEncoding = 'buffer'; @@ -130,76 +106,6 @@ export const kEmptyObject = Object.freeze(Object.create(null)); // return slowCases(enc); // } -export function toArrayBuffer(buf: Buffer): ArrayBuffer { - if (buf?.buffer?.slice) { - return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); - } - const ab = new ArrayBuffer(buf.length); - const view = new Uint8Array(ab); - for (let i = 0; i < buf.length; ++i) { - view[i] = buf[i]!; - } - return ab; -} - -export function bufferLikeToArrayBuffer(buf: BufferLike): ArrayBuffer { - return Buffer.isBuffer(buf) - ? buf.buffer - : ArrayBuffer.isView(buf) - ? buf.buffer - : buf; -} - -export function binaryLikeToArrayBuffer( - input: BinaryLikeNode, // CipherKey adds compat with node types - encoding: string = 'utf-8' -): ArrayBuffer { - if (typeof input === 'string') { - if (encoding === 'buffer') { - throw new Error( - 'Cannot create a buffer from a string with a buffer encoding' - ); - } - - const buffer = Buffer.from(input, encoding); - - return buffer.buffer.slice( - buffer.byteOffset, - buffer.byteOffset + buffer.byteLength - ); - } - - if (Buffer.isBuffer(input)) { - return toArrayBuffer(input); - } - - // TODO add further binary types to BinaryLike, UInt8Array and so for have this array as property - if (ArrayBuffer.isView(input)) { - return input.buffer; - } - - if (!(input instanceof ArrayBuffer)) { - try { - // this is a strange fallback case and input is unknown at this point - // @ts-expect-error - const buffer = Buffer.from(input); - return buffer.buffer.slice( - buffer.byteOffset, - buffer.byteOffset + buffer.byteLength - ); - } catch { - throw 'error'; - } - } - - // TODO: handle if input is KeyObject? - - return input; -} - -export function ab2str(buf: ArrayBuffer, encoding: string = 'hex') { - return Buffer.from(buf).toString(encoding); -} export function validateString(str: any, name?: string): str is string { const isString = typeof str === 'string'; @@ -302,15 +208,6 @@ export function hasAnyNotIn(set: string[], checks: string[]) { return false; } -export function lazyDOMException(message: string, domName: DOMName): Error { - let cause = ''; - if (typeof domName !== 'string') { - cause = `\nCaused by: ${domName.cause}`; - } - - return new Error(`[${domName}]: ${message}${cause}`); -} - // from lib/internal/crypto/util.js // The maximum buffer size that we'll support in the WebCrypto impl From b0b603851ebad20870b28b7f5aaf437523aefca3 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Tue, 10 Sep 2024 00:02:10 -0400 Subject: [PATCH 02/20] more js, prettier fixes --- .../react-native-quick-crypto/.prettierignore | 5 +++ .../eslint.config.js | 8 +++- .../react-native-quick-crypto/package.json | 2 + .../react-native-quick-crypto/src/index.ts | 7 ++-- .../src/keys/index.ts | 6 +-- .../react-native-quick-crypto/src/pbkdf2.ts | 21 +++++----- .../react-native-quick-crypto/src/random.ts | 24 +++++------ .../src/specs/keyObjectHandle.nitro.ts | 16 +++++-- .../src/specs/pbkdf2.nitro.ts | 6 +-- .../src/specs/random.nitro.ts | 6 +-- .../src/utils/hashnames.ts | 2 +- .../src/utils/index.ts | 1 - .../src/utils/types.ts | 42 +++++++++---------- .../test/hashnames.test.ts | 2 +- 14 files changed, 85 insertions(+), 63 deletions(-) create mode 100644 packages/react-native-quick-crypto/.prettierignore diff --git a/packages/react-native-quick-crypto/.prettierignore b/packages/react-native-quick-crypto/.prettierignore new file mode 100644 index 00000000..9dd484b1 --- /dev/null +++ b/packages/react-native-quick-crypto/.prettierignore @@ -0,0 +1,5 @@ +# ts generated files +lib/* + +# holding old code while we migrate to new architecture +zzz/* diff --git a/packages/react-native-quick-crypto/eslint.config.js b/packages/react-native-quick-crypto/eslint.config.js index 2ad00b49..28d81505 100644 --- a/packages/react-native-quick-crypto/eslint.config.js +++ b/packages/react-native-quick-crypto/eslint.config.js @@ -35,6 +35,12 @@ export default typescriptEslint.config( }, // don't lint config files { - ignores: ['.prettierrc.js', '*.config.js', '**/lib/**', '**/test/**', '**/zzz/**'], + ignores: [ + '.prettierrc.js', + '*.config.js', + '**/lib/**', + '**/test/**', + '**/zzz/**', + ], }, ); diff --git a/packages/react-native-quick-crypto/package.json b/packages/react-native-quick-crypto/package.json index 629f920f..d7d8520f 100644 --- a/packages/react-native-quick-crypto/package.json +++ b/packages/react-native-quick-crypto/package.json @@ -32,6 +32,8 @@ "typescript": "tsc --noEmit", "lint": "eslint \"**/*.{js,ts,tsx}\"", "lint-fix": "eslint \"**/*.{js,ts,tsx}\" --fix", + "format": "prettier --check \"**/*.{js,ts,tsx}\"", + "format-fix": "prettier --write \"**/*.{js,ts,tsx}\"", "prepare": "bun clean && bob build", "release-it": "bun prepare && release-it", "test": "jest", diff --git a/packages/react-native-quick-crypto/src/index.ts b/packages/react-native-quick-crypto/src/index.ts index 84bd9798..e7ed75b5 100644 --- a/packages/react-native-quick-crypto/src/index.ts +++ b/packages/react-native-quick-crypto/src/index.ts @@ -2,10 +2,11 @@ import { Buffer } from '@craftzdog/react-native-buffer'; // API imports +import { pbkdf2 } from './pbkdf2'; import * as random from './random'; // utils import -import { utils } from './utils'; +import * as conversion_utils from './utils/conversion'; /** * Loosely matches Node.js {crypto} with some unimplemented functionality. @@ -34,12 +35,12 @@ const QuickCrypto = { // createVerify, // subtle, // constants, - // ...pbkdf2, + ...pbkdf2, ...random, // getCiphers, // getHashes, // webcrypto, - utils, + ...conversion_utils, }; /** diff --git a/packages/react-native-quick-crypto/src/keys/index.ts b/packages/react-native-quick-crypto/src/keys/index.ts index a3bf1ff1..5f101a40 100644 --- a/packages/react-native-quick-crypto/src/keys/index.ts +++ b/packages/react-native-quick-crypto/src/keys/index.ts @@ -1,5 +1,5 @@ -import type { KeyObjectHandle } from "../specs/keyObjectHandle.nitro"; -import type { EncodingOptions, KeyUsage, SubtleAlgorithm } from "../utils"; +import type { KeyObjectHandle } from '../specs/keyObjectHandle.nitro'; +import type { EncodingOptions, KeyUsage, SubtleAlgorithm } from '../utils'; export class CryptoKey { keyObject: KeyObject; @@ -11,7 +11,7 @@ export class CryptoKey { keyObject: KeyObject, keyAlgorithm: SubtleAlgorithm, keyUsages: KeyUsage[], - keyExtractable: boolean + keyExtractable: boolean, ) { this.keyObject = keyObject; this.keyAlgorithm = keyAlgorithm; diff --git a/packages/react-native-quick-crypto/src/pbkdf2.ts b/packages/react-native-quick-crypto/src/pbkdf2.ts index 5df7a9bf..01db457c 100644 --- a/packages/react-native-quick-crypto/src/pbkdf2.ts +++ b/packages/react-native-quick-crypto/src/pbkdf2.ts @@ -1,14 +1,12 @@ import { Buffer } from '@craftzdog/react-native-buffer'; import { NitroModules } from 'react-native-nitro-modules'; -import type { - BinaryLike, -} from './utils'; +import type { BinaryLike } from './utils'; import { HashContext, binaryLikeToArrayBuffer, bufferLikeToArrayBuffer, lazyDOMException, - normalizeHashName + normalizeHashName, } from './utils'; import type { HashAlgorithm, SubtleAlgorithm } from './utils'; import type { Pbkdf2 } from './specs/pbkdf2.nitro'; @@ -58,7 +56,8 @@ export function pbkdf2( const normalizedDigest = normalizeHashName(digest, HashContext.Node); getNative(); - native.pbkdf2( + native + .pbkdf2( sanitizedPassword, sanitizedSalt, iterations, @@ -80,7 +79,7 @@ export function pbkdf2Sync( salt: Salt, iterations: number, keylen: number, - digest?: HashAlgorithm + digest?: HashAlgorithm, ): ArrayBuffer { const sanitizedPassword = sanitizeInput(password, WRONG_PASS); const sanitizedSalt = sanitizeInput(salt, WRONG_SALT); @@ -92,7 +91,7 @@ export function pbkdf2Sync( sanitizedSalt, iterations, keylen, - algo + algo, ); return Buffer.from(result); @@ -106,14 +105,14 @@ const pbkdf2WithDigest = ( iterations: number, keylen: number, digest: HashAlgorithm, - callback: Pbkdf2Callback + callback: Pbkdf2Callback, ) => pbkdf2(password, salt, iterations, keylen, digest, callback); const pbkdf2Promise = promisify(pbkdf2WithDigest); export async function pbkdf2DeriveBits( algorithm: SubtleAlgorithm, baseKey: CryptoKey, - length: number + length: number, ): Promise { const { iterations, hash, salt } = algorithm; const normalizedHash = normalizeHashName(hash); @@ -143,12 +142,12 @@ export async function pbkdf2DeriveBits( sanitizedSalt, iterations, length / 8, - normalizedHash as HashAlgorithm + normalizedHash as HashAlgorithm, ); if (!result) { throw lazyDOMException( 'received bad result from pbkdf2()', - 'OperationError' + 'OperationError', ); } return bufferLikeToArrayBuffer(result); diff --git a/packages/react-native-quick-crypto/src/random.ts b/packages/react-native-quick-crypto/src/random.ts index c524de6f..7820830b 100644 --- a/packages/react-native-quick-crypto/src/random.ts +++ b/packages/react-native-quick-crypto/src/random.ts @@ -16,20 +16,20 @@ function getNative(): Random { export function randomFill( buffer: T, - callback: RandomCallback + callback: RandomCallback, ): void; export function randomFill( buffer: T, offset: number, - callback: RandomCallback + callback: RandomCallback, ): void; export function randomFill( buffer: T, offset: number, size: number, - callback: RandomCallback + callback: RandomCallback, ): void; export function randomFill(buffer: ArrayBufferView, ...rest: unknown[]): void { @@ -39,7 +39,7 @@ export function randomFill(buffer: ArrayBufferView, ...rest: unknown[]): void { const callback = rest[rest.length - 1] as unknown as ( err: Error | null, - buf?: ArrayBuffer + buf?: ArrayBuffer, ) => void; let offset: number = 0; @@ -61,20 +61,20 @@ export function randomFill(buffer: ArrayBufferView, ...rest: unknown[]): void { }, (e: Error) => { callback(e); - } + }, ); } export function randomFillSync( buffer: T, offset?: number, - size?: number + size?: number, ): T; export function randomFillSync( buffer: ArrayBufferView, offset: number = 0, - size?: number + size?: number, ) { getNative(); buffer = abvToArrayBuffer(buffer); @@ -87,12 +87,12 @@ export function randomBytes(size: number): Buffer; export function randomBytes( size: number, - callback: (err: Error | null, buf?: Buffer) => void + callback: (err: Error | null, buf?: Buffer) => void, ): void; export function randomBytes( size: number, - callback?: (err: Error | null, buf?: Buffer) => void + callback?: (err: Error | null, buf?: Buffer) => void, ): void | Buffer { const buf = new Buffer(size); @@ -141,13 +141,13 @@ export function randomInt(max: number): number; export function randomInt( min: number, max: number, - callback: RandomIntCallback + callback: RandomIntCallback, ): void; export function randomInt(min: number, max: number): number; export function randomInt( arg1: number, arg2?: number | RandomIntCallback, - callback?: RandomIntCallback + callback?: RandomIntCallback, ): void | number { // Detect optional min syntax // randomInt(max) @@ -253,7 +253,7 @@ function asyncRefillRandomIntCache() { // callback (errorReceiver) about it. This way, every async call to // randomInt has a chance of being successful, and it avoids complex // exception handling here. - tasks.splice(0).forEach((task) => { + tasks.splice(0).forEach(task => { randomInt(task.min, task.max, task.callback); }); diff --git a/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts b/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts index aca5eea6..c57249c7 100644 --- a/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts +++ b/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts @@ -1,7 +1,17 @@ import { type HybridObject } from 'react-native-nitro-modules'; -import type { AsymmetricKeyType, BinaryLike, JWK, KeyDetail, KeyEncoding, KeyType, KFormatType, NamedCurve } from '../utils'; +import type { + AsymmetricKeyType, + BinaryLike, + JWK, + KeyDetail, + KeyEncoding, + KeyType, + KFormatType, + NamedCurve, +} from '../utils'; -export interface KeyObjectHandle extends HybridObject<{ ios: 'c++'; android: 'c++' }> { +export interface KeyObjectHandle + extends HybridObject<{ ios: 'c++'; android: 'c++' }> { export( format?: KFormatType, type?: KeyEncoding, @@ -20,4 +30,4 @@ export interface KeyObjectHandle extends HybridObject<{ ios: 'c++'; android: 'c+ initECRaw(curveName: string, keyData: ArrayBuffer): boolean; initJwk(keyData: JWK, namedCurve?: NamedCurve): KeyType | undefined; keyDetail(): KeyDetail; -}; \ No newline at end of file +} diff --git a/packages/react-native-quick-crypto/src/specs/pbkdf2.nitro.ts b/packages/react-native-quick-crypto/src/specs/pbkdf2.nitro.ts index 270ff2be..1127f511 100644 --- a/packages/react-native-quick-crypto/src/specs/pbkdf2.nitro.ts +++ b/packages/react-native-quick-crypto/src/specs/pbkdf2.nitro.ts @@ -6,13 +6,13 @@ export interface Pbkdf2 extends HybridObject<{ ios: 'c++'; android: 'c++' }> { salt: ArrayBuffer, iterations: number, keylen: number, - digest: string + digest: string, ) => Promise; pbkdf2Sync: ( password: ArrayBuffer, salt: ArrayBuffer, iterations: number, keylen: number, - digest: string + digest: string, ) => ArrayBuffer; -}; +} diff --git a/packages/react-native-quick-crypto/src/specs/random.nitro.ts b/packages/react-native-quick-crypto/src/specs/random.nitro.ts index fc63c3f9..de8d1bb1 100644 --- a/packages/react-native-quick-crypto/src/specs/random.nitro.ts +++ b/packages/react-native-quick-crypto/src/specs/random.nitro.ts @@ -4,11 +4,11 @@ export interface Random extends HybridObject<{ ios: 'c++'; android: 'c++' }> { randomFill( buffer: ArrayBuffer, offset: number, - size: number + size: number, ): Promise; randomFillSync( buffer: ArrayBuffer, offset: number, - size: number + size: number, ): ArrayBuffer; -}; +} diff --git a/packages/react-native-quick-crypto/src/utils/hashnames.ts b/packages/react-native-quick-crypto/src/utils/hashnames.ts index 94ff028f..57078f13 100644 --- a/packages/react-native-quick-crypto/src/utils/hashnames.ts +++ b/packages/react-native-quick-crypto/src/utils/hashnames.ts @@ -93,4 +93,4 @@ export function normalizeHashName( } } throw new Error(`Invalid Hash Algorithm: ${algo}`); -} \ No newline at end of file +} diff --git a/packages/react-native-quick-crypto/src/utils/index.ts b/packages/react-native-quick-crypto/src/utils/index.ts index 9a43de0e..d16cca11 100644 --- a/packages/react-native-quick-crypto/src/utils/index.ts +++ b/packages/react-native-quick-crypto/src/utils/index.ts @@ -2,4 +2,3 @@ export * from './conversion'; export * from './errors'; export * from './hashnames'; export * from './types'; - diff --git a/packages/react-native-quick-crypto/src/utils/types.ts b/packages/react-native-quick-crypto/src/utils/types.ts index c0f1bbe4..1dfebdda 100644 --- a/packages/react-native-quick-crypto/src/utils/types.ts +++ b/packages/react-native-quick-crypto/src/utils/types.ts @@ -130,28 +130,28 @@ export enum KeyEncoding { export type AsymmetricKeyType = 'rsa' | 'rsa-pss' | 'dsa' | 'ec' | undefined; export type JWK = { - 'kty'?: 'AES' | 'RSA' | 'EC' | 'oct'; - 'use'?: 'sig' | 'enc'; - 'key_ops'?: KeyUsage[]; - 'alg'?: string; // TODO: enumerate these (RFC-7517) - 'crv'?: string; - 'kid'?: string; - 'x5u'?: string; - 'x5c'?: string[]; - 'x5t'?: string; + kty?: 'AES' | 'RSA' | 'EC' | 'oct'; + use?: 'sig' | 'enc'; + key_ops?: KeyUsage[]; + alg?: string; // TODO: enumerate these (RFC-7517) + crv?: string; + kid?: string; + x5u?: string; + x5c?: string[]; + x5t?: string; 'x5t#256'?: string; - 'n'?: string; - 'e'?: string; - 'd'?: string; - 'p'?: string; - 'q'?: string; - 'x'?: string; - 'y'?: string; - 'k'?: string; - 'dp'?: string; - 'dq'?: string; - 'qi'?: string; - 'ext'?: boolean; + n?: string; + e?: string; + d?: string; + p?: string; + q?: string; + x?: string; + y?: string; + k?: string; + dp?: string; + dq?: string; + qi?: string; + ext?: boolean; }; export type KTypePrivate = 'pkcs1' | 'pkcs8' | 'sec1'; diff --git a/packages/react-native-quick-crypto/test/hashnames.test.ts b/packages/react-native-quick-crypto/test/hashnames.test.ts index 0886e75b..95ca910b 100644 --- a/packages/react-native-quick-crypto/test/hashnames.test.ts +++ b/packages/react-native-quick-crypto/test/hashnames.test.ts @@ -12,6 +12,6 @@ test('normalizeHashName happy', () => { test('normalizeHashName sad', () => { expect(normalizeHashName('SHA-2')).toBe('sha-2'); expect(normalizeHashName('NOT-a-hash', HashContext.JwkRsaPss)).toBe( - 'not-a-hash' + 'not-a-hash', ); }); From ae7ad59622ca37481b7b1b95f143f1ed90dd08c3 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Tue, 10 Sep 2024 00:19:02 -0400 Subject: [PATCH 03/20] ready for nitro-codegen --- packages/react-native-quick-crypto/src/index.ts | 5 +++-- packages/react-native-quick-crypto/src/utils/types.ts | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/react-native-quick-crypto/src/index.ts b/packages/react-native-quick-crypto/src/index.ts index e7ed75b5..1da075f9 100644 --- a/packages/react-native-quick-crypto/src/index.ts +++ b/packages/react-native-quick-crypto/src/index.ts @@ -2,7 +2,7 @@ import { Buffer } from '@craftzdog/react-native-buffer'; // API imports -import { pbkdf2 } from './pbkdf2'; +import * as pbkdf2 from './pbkdf2'; import * as random from './random'; // utils import @@ -44,7 +44,8 @@ const QuickCrypto = { }; /** - * Optional. Patch global.crypto with quickcrypto and global.Buffer with react-native-buffer. + * Optional. Patch global.crypto with react-native-quick-crypto and + * global.Buffer with react-native-buffer. */ export const install = () => { // @ts-expect-error copyBytesFrom and poolSizets are missing from react-native-buffer diff --git a/packages/react-native-quick-crypto/src/utils/types.ts b/packages/react-native-quick-crypto/src/utils/types.ts index 1dfebdda..08b62503 100644 --- a/packages/react-native-quick-crypto/src/utils/types.ts +++ b/packages/react-native-quick-crypto/src/utils/types.ts @@ -1,5 +1,5 @@ -import { Buffer } from '@craftzdog/react-native-buffer'; -import { Buffer as SBuffer } from 'safe-buffer'; +import { type Buffer } from '@craftzdog/react-native-buffer'; +import { type Buffer as SBuffer } from 'safe-buffer'; import { type CipherKey } from 'crypto'; // @types/node export type ArrayBufferView = TypedArray | DataView | ArrayBufferLike | Buffer; From c4dbfdb8022ef6423a52172bc8e511627317898b Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Tue, 10 Sep 2024 08:43:18 -0400 Subject: [PATCH 04/20] more pre-nitro type work --- .../src/specs/keyObjectHandle.nitro.ts | 5 ++--- packages/react-native-quick-crypto/src/utils/types.ts | 7 +++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts b/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts index c57249c7..b3bc0c16 100644 --- a/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts +++ b/packages/react-native-quick-crypto/src/specs/keyObjectHandle.nitro.ts @@ -1,7 +1,6 @@ import { type HybridObject } from 'react-native-nitro-modules'; import type { AsymmetricKeyType, - BinaryLike, JWK, KeyDetail, KeyEncoding, @@ -16,7 +15,7 @@ export interface KeyObjectHandle format?: KFormatType, type?: KeyEncoding, cipher?: string, - passphrase?: BinaryLike, + passphrase?: ArrayBuffer, ): ArrayBuffer; exportJwk(key: JWK, handleRsaPss: boolean): JWK; getAsymmetricKeyType(): AsymmetricKeyType; @@ -25,7 +24,7 @@ export interface KeyObjectHandle key: string | ArrayBuffer, format?: KFormatType, type?: KeyEncoding, - passphrase?: BinaryLike, + passphrase?: ArrayBuffer, ): boolean; initECRaw(curveName: string, keyData: ArrayBuffer): boolean; initJwk(keyData: JWK, namedCurve?: NamedCurve): KeyType | undefined; diff --git a/packages/react-native-quick-crypto/src/utils/types.ts b/packages/react-native-quick-crypto/src/utils/types.ts index 08b62503..8d53d921 100644 --- a/packages/react-native-quick-crypto/src/utils/types.ts +++ b/packages/react-native-quick-crypto/src/utils/types.ts @@ -129,9 +129,12 @@ export enum KeyEncoding { export type AsymmetricKeyType = 'rsa' | 'rsa-pss' | 'dsa' | 'ec' | undefined; +export type JWKkty = 'AES' | 'RSA' | 'EC' | 'oct'; +export type JWKuse = 'sig' | 'enc'; + export type JWK = { - kty?: 'AES' | 'RSA' | 'EC' | 'oct'; - use?: 'sig' | 'enc'; + kty?: JWKkty; + use?: JWKuse; key_ops?: KeyUsage[]; alg?: string; // TODO: enumerate these (RFC-7517) crv?: string; From 3268534d2ba5d534cc3e399482bc8595b34f2e97 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Tue, 10 Sep 2024 10:20:23 -0400 Subject: [PATCH 05/20] still pre-nitrogen --- packages/react-native-quick-crypto/src/utils/types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-native-quick-crypto/src/utils/types.ts b/packages/react-native-quick-crypto/src/utils/types.ts index 8d53d921..0cff7b63 100644 --- a/packages/react-native-quick-crypto/src/utils/types.ts +++ b/packages/react-native-quick-crypto/src/utils/types.ts @@ -129,10 +129,10 @@ export enum KeyEncoding { export type AsymmetricKeyType = 'rsa' | 'rsa-pss' | 'dsa' | 'ec' | undefined; -export type JWKkty = 'AES' | 'RSA' | 'EC' | 'oct'; -export type JWKuse = 'sig' | 'enc'; +type JWKkty = 'AES' | 'RSA' | 'EC' | 'oct'; +type JWKuse = 'sig' | 'enc'; -export type JWK = { +export interface JWK { kty?: JWKkty; use?: JWKuse; key_ops?: KeyUsage[]; From e05313cfeea0c9e5eaea502fdf466cc02a029d6b Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Mon, 16 Sep 2024 09:59:33 -0400 Subject: [PATCH 06/20] nitro bump & new generation --- bun.lockb | Bin 550264 -> 549848 bytes example/package.json | 2 +- .../src/testing/tests/random/random_tests.ts | 8 +- packages/react-native-quick-crypto/nitro.json | 8 +- .../android/QuickCrypto+autolinking.cmake | 8 +- .../android/QuickCrypto+autolinking.gradle | 3 +- .../generated/android/QuickCryptoOnLoad.cpp | 40 +++ .../generated/android/QuickCryptoOnLoad.hpp | 24 ++ .../generated/android/QuickCryptoOnLoad.kt | 1 + .../generated/ios/QuickCrypto+autolinking.rb | 5 +- .../ios/QuickCrypto-Swift-Cxx-Bridge.cpp | 3 +- .../ios/QuickCrypto-Swift-Cxx-Bridge.hpp | 281 +++++++++++++++++- .../ios/QuickCrypto-Swift-Cxx-Umbrella.hpp | 49 ++- .../generated/ios/QuickCryptoAutolinking.mm | 35 +++ .../ios/QuickCryptoAutolinking.swift | 10 + .../shared/c++/AsymmetricKeyType.hpp | 86 ++++++ .../shared/c++/HybridKeyObjectHandleSpec.cpp | 27 ++ .../shared/c++/HybridKeyObjectHandleSpec.hpp | 90 ++++++ .../generated/shared/c++/HybridPbkdf2Spec.cpp | 24 ++ .../generated/shared/c++/HybridPbkdf2Spec.hpp | 66 ++++ .../generated/shared/c++/HybridRandomSpec.cpp | 3 +- .../generated/shared/c++/HybridRandomSpec.hpp | 8 +- .../nitrogen/generated/shared/c++/JWK.hpp | 162 ++++++++++ .../nitrogen/generated/shared/c++/JWKkty.hpp | 86 ++++++ .../nitrogen/generated/shared/c++/JWKuse.hpp | 78 +++++ .../generated/shared/c++/KFormatType.hpp | 65 ++++ .../generated/shared/c++/KeyDetail.hpp | 93 ++++++ .../generated/shared/c++/KeyEncoding.hpp | 66 ++++ .../nitrogen/generated/shared/c++/KeyType.hpp | 65 ++++ .../generated/shared/c++/KeyUsage.hpp | 102 +++++++ .../generated/shared/c++/NamedCurve.hpp | 82 +++++ .../react-native-quick-crypto/package.json | 5 +- .../src/utils/types.ts | 8 +- 33 files changed, 1560 insertions(+), 33 deletions(-) create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.cpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.kt create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCryptoAutolinking.mm create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCryptoAutolinking.swift create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridPbkdf2Spec.cpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridPbkdf2Spec.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWK.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWKkty.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWKuse.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KFormatType.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyDetail.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyEncoding.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyType.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyUsage.hpp create mode 100644 packages/react-native-quick-crypto/nitrogen/generated/shared/c++/NamedCurve.hpp diff --git a/bun.lockb b/bun.lockb index d712cd16688531f380e4ecdda968e8c689d916aa..403b895d87469c64e6cf3ed2627532c42a4b31da 100755 GIT binary patch delta 32186 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 delta 32241 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 HB6s|MDN||r diff --git a/example/package.json b/example/package.json index 4a4e8a9c..ba22af1e 100644 --- a/example/package.json +++ b/example/package.json @@ -29,7 +29,7 @@ "react": "^18.3.1", "react-native": "^0.74.5", "react-native-bouncy-checkbox": "4.0.1", - "react-native-nitro-modules": "0.7.0", + "react-native-nitro-modules": "0.9.0", "react-native-quick-base64": "2.1.2", "react-native-quick-crypto": "*", "react-native-safe-area-context": "4.10.8", diff --git a/example/src/testing/tests/random/random_tests.ts b/example/src/testing/tests/random/random_tests.ts index 86ca111c..bd833fc2 100644 --- a/example/src/testing/tests/random/random_tests.ts +++ b/example/src/testing/tests/random/random_tests.ts @@ -7,7 +7,7 @@ import { Buffer } from '@craftzdog/react-native-buffer' import { assert } from 'chai' import type { Done } from 'mocha' -const { ab2str, abvToArrayBuffer } = crypto.utils; +const { ab2str, abvToArrayBuffer } = crypto; describe('random', () => { ;[crypto.randomBytes, crypto.pseudoRandomBytes].forEach((f) => { @@ -591,10 +591,12 @@ describe('random', () => { `It must be <= ${MAX_RANGE}. ` + 'Received 281_474_976_710_656' ) - }) - ;[true, NaN, [], 10].forEach((val) => { + }); + + [true, NaN, [], 10].forEach((val) => { it(`expect type error: ${val}`, () => { assert.throws( + // @ts-expect-error - testing bad args () => crypto.randomInt(0, 1, val), /callback must be a function or undefined/ ) diff --git a/packages/react-native-quick-crypto/nitro.json b/packages/react-native-quick-crypto/nitro.json index d3b9d531..42d6d1fe 100644 --- a/packages/react-native-quick-crypto/nitro.json +++ b/packages/react-native-quick-crypto/nitro.json @@ -7,5 +7,11 @@ "android": { "androidNamespace": ["crypto"], "androidCxxLibName": "QuickCrypto" - } + }, + "autolinking": { + "HybridRandom": { + "cpp": "HybridRandom" + } + }, + "ignorePaths": ["node_modules"] } diff --git a/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCrypto+autolinking.cmake b/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCrypto+autolinking.cmake index c3c08c86..ba45c08f 100644 --- a/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCrypto+autolinking.cmake +++ b/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCrypto+autolinking.cmake @@ -1,8 +1,7 @@ # # QuickCrypto+autolinking.cmake -# Tue Aug 13 2024 # This file was generated by nitrogen. DO NOT MODIFY THIS FILE. -# https://github.com/mrousavy/react-native-nitro +# https://github.com/mrousavy/nitro # Copyright © 2024 Marc Rousavy @ Margelo # @@ -18,13 +17,18 @@ include_directories( "../nitrogen/generated/shared/c++" "../nitrogen/generated/android/c++" + "../nitrogen/generated/android/" ) # Add all .cpp sources that were generated by Nitrogen target_sources( # CMake project name (Android C++ library name) QuickCrypto PRIVATE + # Autolinking Setup + ../nitrogen/generated/android/QuickCryptoOnLoad.cpp # Shared Nitrogen C++ sources + ../nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp + ../nitrogen/generated/shared/c++/HybridPbkdf2Spec.cpp ../nitrogen/generated/shared/c++/HybridRandomSpec.cpp # Android-specific Nitrogen C++ sources diff --git a/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCrypto+autolinking.gradle b/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCrypto+autolinking.gradle index 636b86ae..437a6f80 100644 --- a/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCrypto+autolinking.gradle +++ b/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCrypto+autolinking.gradle @@ -1,8 +1,7 @@ /// /// QuickCrypto+autolinking.gradle -/// Tue Aug 13 2024 /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. -/// https://github.com/mrousavy/react-native-nitro +/// https://github.com/mrousavy/nitro /// Copyright © 2024 Marc Rousavy @ Margelo /// diff --git a/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.cpp b/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.cpp new file mode 100644 index 00000000..cd78fc9b --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.cpp @@ -0,0 +1,40 @@ +/// +/// QuickCryptoOnLoad.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#include "QuickCryptoOnLoad.hpp" + +#include +#include +#include + +#include "HybridRandom.hpp" + +namespace margelo::nitro::crypto { + +int initialize(JavaVM* vm) { + using namespace margelo::nitro; + using namespace margelo::nitro::crypto; + using namespace facebook; + + return facebook::jni::initialize(vm, [] { + // Register native JNI methods + + + // Register Nitro Hybrid Objects + HybridObjectRegistry::registerHybridObjectConstructor( + "HybridRandom", + []() -> std::shared_ptr { + static_assert(std::is_default_constructible_v, + "The HybridObject \"HybridRandom\" is not default-constructible! " + "Create a public constructor that takes zero arguments to be able to autolink this HybridObject."); + return std::make_shared(); + } + ); + }); +} + +} // namespace margelo::nitro::crypto diff --git a/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.hpp b/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.hpp new file mode 100644 index 00000000..8049a615 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.hpp @@ -0,0 +1,24 @@ +/// +/// QuickCryptoOnLoad.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#include + +namespace margelo::nitro::crypto { + + /** + * Initializes the native (C++) part of QuickCrypto, and autolinks all Hybrid Objects. + * Call this in your `JNI_OnLoad` function (probably inside `cpp-adapter.cpp`). + * Example: + * ```cpp (cpp-adapter.cpp) + * JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { + * return margelo::nitro::crypto::initialize(vm); + * } + * ``` + */ + int initialize(JavaVM* vm); + +} // namespace margelo::nitro::crypto diff --git a/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.kt b/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.kt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/android/QuickCryptoOnLoad.kt @@ -0,0 +1 @@ + diff --git a/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto+autolinking.rb b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto+autolinking.rb index 17592804..a792bc67 100644 --- a/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto+autolinking.rb +++ b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto+autolinking.rb @@ -1,8 +1,7 @@ # # QuickCrypto+autolinking.rb -# Tue Aug 13 2024 # This file was generated by nitrogen. DO NOT MODIFY THIS FILE. -# https://github.com/mrousavy/react-native-nitro +# https://github.com/mrousavy/nitro # Copyright © 2024 Marc Rousavy @ Margelo # @@ -30,7 +29,7 @@ def add_nitrogen_files(spec) # Generated cross-platform specs "nitrogen/generated/shared/**/*.{h,hpp,c,cpp,swift}", # Generated bridges for the cross-platform specs - "nitrogen/generated/ios/**/*.{h,hpp,c,cpp,swift}", + "nitrogen/generated/ios/**/*.{h,hpp,c,cpp,mm,swift}", ] current_public_header_files = spec.attributes_hash['public_header_files'] || [] diff --git a/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.cpp b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.cpp index 6a0798a5..ca409639 100644 --- a/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.cpp +++ b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.cpp @@ -1,8 +1,7 @@ /// /// QuickCrypto-Swift-Cxx-Bridge.cpp -/// Tue Aug 13 2024 /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. -/// https://github.com/mrousavy/react-native-nitro +/// https://github.com/mrousavy/nitro /// Copyright © 2024 Marc Rousavy @ Margelo /// diff --git a/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.hpp b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.hpp index 55acf677..667f9d2a 100644 --- a/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.hpp +++ b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.hpp @@ -1,18 +1,84 @@ /// /// QuickCrypto-Swift-Cxx-Bridge.hpp -/// Tue Aug 13 2024 /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. -/// https://github.com/mrousavy/react-native-nitro +/// https://github.com/mrousavy/nitro /// Copyright © 2024 Marc Rousavy @ Margelo /// #pragma once // Forward declarations of C++ defined types - +// Forward declaration of `ArrayBufferHolder` to properly resolve imports. +namespace NitroModules { class ArrayBufferHolder; } +// Forward declaration of `ArrayBuffer` to properly resolve imports. +namespace NitroModules { class ArrayBuffer; } +// Forward declaration of `JWKkty` to properly resolve imports. +namespace margelo::nitro::crypto { enum class JWKkty; } +// Forward declaration of `JWKuse` to properly resolve imports. +namespace margelo::nitro::crypto { enum class JWKuse; } +// Forward declaration of `KFormatType` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KFormatType; } +// Forward declaration of `KeyEncoding` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KeyEncoding; } +// Forward declaration of `KeyType` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KeyType; } +// Forward declaration of `KeyUsage` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KeyUsage; } +// Forward declaration of `NamedCurve` to properly resolve imports. +namespace margelo::nitro::crypto { enum class NamedCurve; } // Include C++ defined types - +#if __has_include("JWKkty.hpp") + #include "JWKkty.hpp" +#endif +#if __has_include("JWKuse.hpp") + #include "JWKuse.hpp" +#endif +#if __has_include("KFormatType.hpp") + #include "KFormatType.hpp" +#endif +#if __has_include("KeyEncoding.hpp") + #include "KeyEncoding.hpp" +#endif +#if __has_include("KeyType.hpp") + #include "KeyType.hpp" +#endif +#if __has_include("KeyUsage.hpp") + #include "KeyUsage.hpp" +#endif +#if __has_include("NamedCurve.hpp") + #include "NamedCurve.hpp" +#endif +#if __has_include() + #include +#endif +#if __has_include() + #include +#endif +#if __has_include() + #include +#endif +#if __has_include() + #include +#endif +#if __has_include() + #include +#endif +#if __has_include() + #include +#endif +#if __has_include() + #include +#endif +#if __has_include() + #include +#endif +#if __has_include() + #include +#endif +#if __has_include() + #include +#endif /** * Contains specialized versions of C++ templated types so they can be accessed from Swift, @@ -20,6 +86,213 @@ */ namespace margelo::nitro::crypto::bridge::swift { + /** + * Specialized version of `std::optional`. + */ + using std__optional_KFormatType_ = std::optional; + inline std::optional create_std__optional_KFormatType_(const KFormatType& value) { + return std::optional(value); + } + + /** + * Specialized version of `std::optional`. + */ + using std__optional_KeyEncoding_ = std::optional; + inline std::optional create_std__optional_KeyEncoding_(const KeyEncoding& value) { + return std::optional(value); + } + + /** + * Specialized version of `std::optional`. + */ + using std__optional_std__string_ = std::optional; + inline std::optional create_std__optional_std__string_(const std::string& value) { + return std::optional(value); + } + + /** + * Specialized version of `std::optional>`. + */ + using std__optional_std__shared_ptr_ArrayBuffer__ = std::optional>; + inline std::optional> create_std__optional_std__shared_ptr_ArrayBuffer__(const std::shared_ptr& value) { + return std::optional>(value); + } + + /** + * Specialized version of `std::optional`. + */ + using std__optional_JWKkty_ = std::optional; + inline std::optional create_std__optional_JWKkty_(const JWKkty& value) { + return std::optional(value); + } + + /** + * Specialized version of `std::optional`. + */ + using std__optional_JWKuse_ = std::optional; + inline std::optional create_std__optional_JWKuse_(const JWKuse& value) { + return std::optional(value); + } + + /** + * Specialized version of `std::vector`. + */ + using std__vector_KeyUsage_ = std::vector; + inline std::vector create_std__vector_KeyUsage_(size_t size) { + std::vector vector; + vector.reserve(size); + return vector; + } + + /** + * Specialized version of `std::optional>`. + */ + using std__optional_std__vector_KeyUsage__ = std::optional>; + inline std::optional> create_std__optional_std__vector_KeyUsage__(const std::vector& value) { + return std::optional>(value); + } + + /** + * Specialized version of `std::vector`. + */ + using std__vector_std__string_ = std::vector; + inline std::vector create_std__vector_std__string_(size_t size) { + std::vector vector; + vector.reserve(size); + return vector; + } + + /** + * Specialized version of `std::optional>`. + */ + using std__optional_std__vector_std__string__ = std::optional>; + inline std::optional> create_std__optional_std__vector_std__string__(const std::vector& value) { + return std::optional>(value); + } + + /** + * Specialized version of `std::optional`. + */ + using std__optional_bool_ = std::optional; + inline std::optional create_std__optional_bool_(const bool& value) { + return std::optional(value); + } + + /** + * Specialized version of `std::variant>`. + */ + using std__variant_std__string__std__shared_ptr_ArrayBuffer__ = std::variant>; + inline std::variant> create_std__variant_std__string__std__shared_ptr_ArrayBuffer__(const std::string& value) { + return value; + } + inline std::variant> create_std__variant_std__string__std__shared_ptr_ArrayBuffer__(const std::shared_ptr& value) { + return value; + } + inline std::string get_std__variant_std__string__std__shared_ptr_ArrayBuffer___0(const std::variant>& variant) { + return std::get<0>(variant); + } + inline std::shared_ptr get_std__variant_std__string__std__shared_ptr_ArrayBuffer___1(const std::variant>& variant) { + return std::get<1>(variant); + } + + /** + * Specialized version of `std::optional`. + */ + using std__optional_KeyType_ = std::optional; + inline std::optional create_std__optional_KeyType_(const KeyType& value) { + return std::optional(value); + } + + /** + * Specialized version of `std::optional`. + */ + using std__optional_NamedCurve_ = std::optional; + inline std::optional create_std__optional_NamedCurve_(const NamedCurve& value) { + return std::optional(value); + } + + /** + * Specialized version of `std::optional`. + */ + using std__optional_double_ = std::optional; + inline std::optional create_std__optional_double_(const double& value) { + return std::optional(value); + } + + /** + * Specialized version of `PromiseHolder>`. + */ + using PromiseHolder_std__shared_ptr_ArrayBuffer__ = PromiseHolder>; + inline PromiseHolder> create_PromiseHolder_std__shared_ptr_ArrayBuffer__() { + return PromiseHolder>(); + } + + /** + * Specialized version of `std::function>>(const std::shared_ptr&, const std::shared_ptr&, double, double, const std::string&)>`. + */ + using Func_std__future_std__future_std__shared_ptr_ArrayBuffer____std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string = std::function>>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)>; + /** + * Wrapper class for a `std::function>>(const std::shared_ptr& / * password * /, const std::shared_ptr& / * salt * /, double / * iterations * /, double / * keylen * /, const std::string& / * digest * /)>`, this can be used from Swift. + */ + class Func_std__future_std__future_std__shared_ptr_ArrayBuffer____std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string_Wrapper { + public: + explicit Func_std__future_std__future_std__shared_ptr_ArrayBuffer____std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string_Wrapper(const std::function>>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)>& func): function(func) {} + explicit Func_std__future_std__future_std__shared_ptr_ArrayBuffer____std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string_Wrapper(std::function>>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)>&& func): function(std::move(func)) {} + + PromiseHolder>> call(ArrayBufferHolder password, ArrayBufferHolder salt, double iterations, double keylen, std::string digest) const { + auto result = function(password.getArrayBuffer(), salt.getArrayBuffer(), iterations, keylen, digest); + return []() -> PromiseHolder>> { throw std::runtime_error("Promise<..> cannot be converted to Swift yet!"); }(); + } + + std::function>>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)> function; + }; + inline Func_std__future_std__future_std__shared_ptr_ArrayBuffer____std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string create_Func_std__future_std__future_std__shared_ptr_ArrayBuffer____std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string(void* closureHolder, PromiseHolder>>(*call)(void* /* closureHolder */, ArrayBufferHolder, ArrayBufferHolder, double, double, std::string), void(*destroy)(void*)) { + std::shared_ptr sharedClosureHolder(closureHolder, destroy); + return Func_std__future_std__future_std__shared_ptr_ArrayBuffer____std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string([sharedClosureHolder, call](const std::shared_ptr& password, const std::shared_ptr& salt, double iterations, double keylen, const std::string& digest) -> std::future>> { + auto result = call(sharedClosureHolder.get(), ArrayBufferHolder(password), ArrayBufferHolder(salt), iterations, keylen, digest); + return result.getFuture(); + }); + } + inline std::shared_ptr share_Func_std__future_std__future_std__shared_ptr_ArrayBuffer____std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string(const Func_std__future_std__future_std__shared_ptr_ArrayBuffer____std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string& value) { + return std::make_shared(value); + } + + /** + * Specialized version of `PromiseHolder>>`. + */ + using PromiseHolder_std__future_std__shared_ptr_ArrayBuffer___ = PromiseHolder>>; + inline PromiseHolder>> create_PromiseHolder_std__future_std__shared_ptr_ArrayBuffer___() { + return PromiseHolder>>(); + } + + /** + * Specialized version of `std::function>(const std::shared_ptr&, const std::shared_ptr&, double, double, const std::string&)>`. + */ + using Func_std__future_std__shared_ptr_ArrayBuffer___std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string = std::function>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)>; + /** + * Wrapper class for a `std::function>(const std::shared_ptr& / * password * /, const std::shared_ptr& / * salt * /, double / * iterations * /, double / * keylen * /, const std::string& / * digest * /)>`, this can be used from Swift. + */ + class Func_std__future_std__shared_ptr_ArrayBuffer___std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string_Wrapper { + public: + explicit Func_std__future_std__shared_ptr_ArrayBuffer___std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string_Wrapper(const std::function>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)>& func): function(func) {} + explicit Func_std__future_std__shared_ptr_ArrayBuffer___std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string_Wrapper(std::function>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)>&& func): function(std::move(func)) {} + + PromiseHolder> call(ArrayBufferHolder password, ArrayBufferHolder salt, double iterations, double keylen, std::string digest) const { + auto result = function(password.getArrayBuffer(), salt.getArrayBuffer(), iterations, keylen, digest); + return []() -> PromiseHolder> { throw std::runtime_error("Promise<..> cannot be converted to Swift yet!"); }(); + } + std::function>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)> function; + }; + inline Func_std__future_std__shared_ptr_ArrayBuffer___std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string create_Func_std__future_std__shared_ptr_ArrayBuffer___std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string(void* closureHolder, PromiseHolder>(*call)(void* /* closureHolder */, ArrayBufferHolder, ArrayBufferHolder, double, double, std::string), void(*destroy)(void*)) { + std::shared_ptr sharedClosureHolder(closureHolder, destroy); + return Func_std__future_std__shared_ptr_ArrayBuffer___std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string([sharedClosureHolder, call](const std::shared_ptr& password, const std::shared_ptr& salt, double iterations, double keylen, const std::string& digest) -> std::future> { + auto result = call(sharedClosureHolder.get(), ArrayBufferHolder(password), ArrayBufferHolder(salt), iterations, keylen, digest); + return result.getFuture(); + }); + } + inline std::shared_ptr share_Func_std__future_std__shared_ptr_ArrayBuffer___std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string(const Func_std__future_std__shared_ptr_ArrayBuffer___std__shared_ptr_ArrayBuffer__std__shared_ptr_ArrayBuffer__double_double_std__string& value) { + return std::make_shared(value); + } } // namespace margelo::nitro::crypto::bridge::swift diff --git a/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Umbrella.hpp b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Umbrella.hpp index 8898cd3a..a98d458f 100644 --- a/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Umbrella.hpp +++ b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Umbrella.hpp @@ -1,8 +1,7 @@ /// /// QuickCrypto-Swift-Cxx-Umbrella.hpp -/// Tue Aug 13 2024 /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. -/// https://github.com/mrousavy/react-native-nitro +/// https://github.com/mrousavy/nitro /// Copyright © 2024 Marc Rousavy @ Margelo /// @@ -11,19 +10,63 @@ // Forward declarations of C++ defined types // Forward declaration of `ArrayBuffer` to properly resolve imports. namespace NitroModules { class ArrayBuffer; } +// Forward declaration of `AsymmetricKeyType` to properly resolve imports. +namespace margelo::nitro::crypto { enum class AsymmetricKeyType; } +// Forward declaration of `JWK` to properly resolve imports. +namespace margelo::nitro::crypto { struct JWK; } +// Forward declaration of `JWKkty` to properly resolve imports. +namespace margelo::nitro::crypto { enum class JWKkty; } +// Forward declaration of `JWKuse` to properly resolve imports. +namespace margelo::nitro::crypto { enum class JWKuse; } +// Forward declaration of `KFormatType` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KFormatType; } +// Forward declaration of `KeyDetail` to properly resolve imports. +namespace margelo::nitro::crypto { struct KeyDetail; } +// Forward declaration of `KeyEncoding` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KeyEncoding; } +// Forward declaration of `KeyType` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KeyType; } +// Forward declaration of `KeyUsage` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KeyUsage; } +// Forward declaration of `NamedCurve` to properly resolve imports. +namespace margelo::nitro::crypto { enum class NamedCurve; } // Include C++ defined types +#include "AsymmetricKeyType.hpp" +#include "JWK.hpp" +#include "JWKkty.hpp" +#include "JWKuse.hpp" +#include "KFormatType.hpp" +#include "KeyDetail.hpp" +#include "KeyEncoding.hpp" +#include "KeyType.hpp" +#include "KeyUsage.hpp" +#include "NamedCurve.hpp" #include +#include +#include +#include +#include +#include +#include // C++ helpers for Swift #include "QuickCrypto-Swift-Cxx-Bridge.hpp" +// Common C++ types used in Swift +#include +#include +#include +#include + // Forward declarations of Swift defined types // Include Swift defined types #if __has_include("QuickCrypto-Swift.h") +// This header is generated by Xcode/Swift on every app build. +// If it cannot be found, make sure the Swift module's name (= podspec name) is actually "QuickCrypto". #include "QuickCrypto-Swift.h" #else -#error QuickCrypto's autogenerated Swift header cannot be found! Make sure the Swift module's name is actually "QuickCrypto", and try building the app first. +#error QuickCrypto's autogenerated Swift header cannot be found! Make sure the Swift module's name (= podspec name) is actually "QuickCrypto", and try building the app first. #endif diff --git a/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCryptoAutolinking.mm b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCryptoAutolinking.mm new file mode 100644 index 00000000..8d36ca8c --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCryptoAutolinking.mm @@ -0,0 +1,35 @@ +/// +/// QuickCryptoAutolinking.mm +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#import +#import + +#import + +#include "HybridRandom.hpp" + +@interface QuickCryptoAutolinking : NSObject +@end + +@implementation QuickCryptoAutolinking + ++ (void) load { + using namespace margelo::nitro; + using namespace margelo::nitro::crypto; + + HybridObjectRegistry::registerHybridObjectConstructor( + "HybridRandom", + []() -> std::shared_ptr { + static_assert(std::is_default_constructible_v, + "The HybridObject \"HybridRandom\" is not default-constructible! " + "Create a public constructor that takes zero arguments to be able to autolink this HybridObject."); + return std::make_shared(); + } + ); +} + +@end diff --git a/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCryptoAutolinking.swift b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCryptoAutolinking.swift new file mode 100644 index 00000000..d35b608e --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCryptoAutolinking.swift @@ -0,0 +1,10 @@ +/// +/// QuickCryptoAutolinking.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +public final class QuickCryptoAutolinking { + +} diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp new file mode 100644 index 00000000..5505eec5 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp @@ -0,0 +1,86 @@ +/// +/// AsymmetricKeyType.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::crypto { + + /** + * An enum which can be represented as a JavaScript union (AsymmetricKeyType). + */ + enum class AsymmetricKeyType { + RSA SWIFT_NAME(rsa) = 0, + RSA_PSS SWIFT_NAME(rsaPss) = 1, + DSA SWIFT_NAME(dsa) = 2, + EC SWIFT_NAME(ec) = 3, + } CLOSED_ENUM; + +} // namespace margelo::nitro::crypto + +namespace margelo::nitro { + + using namespace margelo::nitro::crypto; + + // C++ AsymmetricKeyType <> JS AsymmetricKeyType (union) + template <> + struct JSIConverter { + static inline AsymmetricKeyType fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + std::string unionValue = JSIConverter::fromJSI(runtime, arg); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("rsa"): return AsymmetricKeyType::RSA; + case hashString("rsa-pss"): return AsymmetricKeyType::RSA_PSS; + case hashString("dsa"): return AsymmetricKeyType::DSA; + case hashString("ec"): return AsymmetricKeyType::EC; + default: [[unlikely]] + throw std::runtime_error("Cannot convert \"" + unionValue + "\" to enum AsymmetricKeyType - invalid value!"); + } + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, AsymmetricKeyType arg) { + switch (arg) { + case AsymmetricKeyType::RSA: return JSIConverter::toJSI(runtime, "rsa"); + case AsymmetricKeyType::RSA_PSS: return JSIConverter::toJSI(runtime, "rsa-pss"); + case AsymmetricKeyType::DSA: return JSIConverter::toJSI(runtime, "dsa"); + case AsymmetricKeyType::EC: return JSIConverter::toJSI(runtime, "ec"); + default: [[unlikely]] + throw std::runtime_error("Cannot convert AsymmetricKeyType to JS - invalid value: " + + std::to_string(static_cast(arg)) + "!"); + } + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isString()) { + return false; + } + std::string unionValue = JSIConverter::fromJSI(runtime, value); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("rsa"): + case hashString("rsa-pss"): + case hashString("dsa"): + case hashString("ec"): + return true; + default: + return false; + } + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp new file mode 100644 index 00000000..95b571f7 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp @@ -0,0 +1,27 @@ +/// +/// HybridKeyObjectHandleSpec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#include "HybridKeyObjectHandleSpec.hpp" + +namespace margelo::nitro::crypto { + + void HybridKeyObjectHandleSpec::loadHybridMethods() { + // load base methods/properties + HybridObject::loadHybridMethods(); + // load custom methods/properties + registerHybrids(this, [](Prototype& prototype) { + prototype.registerHybridMethod("export", &HybridKeyObjectHandleSpec::export); + prototype.registerHybridMethod("exportJwk", &HybridKeyObjectHandleSpec::exportJwk); + prototype.registerHybridMethod("getAsymmetricKeyType", &HybridKeyObjectHandleSpec::getAsymmetricKeyType); + prototype.registerHybridMethod("init", &HybridKeyObjectHandleSpec::init); + prototype.registerHybridMethod("initECRaw", &HybridKeyObjectHandleSpec::initECRaw); + prototype.registerHybridMethod("initJwk", &HybridKeyObjectHandleSpec::initJwk); + prototype.registerHybridMethod("keyDetail", &HybridKeyObjectHandleSpec::keyDetail); + }); + } + +} // namespace margelo::nitro::crypto diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp new file mode 100644 index 00000000..0f4be436 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp @@ -0,0 +1,90 @@ +/// +/// HybridKeyObjectHandleSpec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +// Forward declaration of `ArrayBuffer` to properly resolve imports. +namespace NitroModules { class ArrayBuffer; } +// Forward declaration of `KFormatType` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KFormatType; } +// Forward declaration of `KeyEncoding` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KeyEncoding; } +// Forward declaration of `JWK` to properly resolve imports. +namespace margelo::nitro::crypto { struct JWK; } +// Forward declaration of `AsymmetricKeyType` to properly resolve imports. +namespace margelo::nitro::crypto { enum class AsymmetricKeyType; } +// Forward declaration of `KeyType` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KeyType; } +// Forward declaration of `NamedCurve` to properly resolve imports. +namespace margelo::nitro::crypto { enum class NamedCurve; } +// Forward declaration of `KeyDetail` to properly resolve imports. +namespace margelo::nitro::crypto { struct KeyDetail; } + +#include +#include +#include "KFormatType.hpp" +#include "KeyEncoding.hpp" +#include +#include "JWK.hpp" +#include "AsymmetricKeyType.hpp" +#include "KeyType.hpp" +#include +#include "NamedCurve.hpp" +#include "KeyDetail.hpp" + +namespace margelo::nitro::crypto { + + using namespace margelo::nitro; + + /** + * An abstract base class for `KeyObjectHandle` + * Inherit this class to create instances of `HybridKeyObjectHandleSpec` in C++. + * @example + * ```cpp + * class HybridKeyObjectHandle: public HybridKeyObjectHandleSpec { + * // ... + * }; + * ``` + */ + class HybridKeyObjectHandleSpec: public virtual HybridObject { + public: + // Constructor + explicit HybridKeyObjectHandleSpec(): HybridObject(TAG) { } + + // Destructor + virtual ~HybridKeyObjectHandleSpec() { } + + public: + // Properties + + + public: + // Methods + virtual std::shared_ptr export(std::optional format, std::optional type, const std::optional& cipher, const std::optional>& passphrase) = 0; + virtual JWK exportJwk(const JWK& key, bool handleRsaPss) = 0; + virtual AsymmetricKeyType getAsymmetricKeyType() = 0; + virtual bool init(KeyType keyType, const std::variant>& key, std::optional format, std::optional type, const std::optional>& passphrase) = 0; + virtual bool initECRaw(const std::string& curveName, const std::shared_ptr& keyData) = 0; + virtual std::optional initJwk(const JWK& keyData, std::optional namedCurve) = 0; + virtual KeyDetail keyDetail() = 0; + + protected: + // Hybrid Setup + void loadHybridMethods() override; + + protected: + // Tag for logging + static constexpr auto TAG = "KeyObjectHandle"; + }; + +} // namespace margelo::nitro::crypto diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridPbkdf2Spec.cpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridPbkdf2Spec.cpp new file mode 100644 index 00000000..46242e10 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridPbkdf2Spec.cpp @@ -0,0 +1,24 @@ +/// +/// HybridPbkdf2Spec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#include "HybridPbkdf2Spec.hpp" + +namespace margelo::nitro::crypto { + + void HybridPbkdf2Spec::loadHybridMethods() { + // load base methods/properties + HybridObject::loadHybridMethods(); + // load custom methods/properties + registerHybrids(this, [](Prototype& prototype) { + prototype.registerHybridGetter("pbkdf2", &HybridPbkdf2Spec::getPbkdf2); + prototype.registerHybridSetter("pbkdf2", &HybridPbkdf2Spec::setPbkdf2); + prototype.registerHybridGetter("pbkdf2Sync", &HybridPbkdf2Spec::getPbkdf2Sync); + prototype.registerHybridSetter("pbkdf2Sync", &HybridPbkdf2Spec::setPbkdf2Sync); + }); + } + +} // namespace margelo::nitro::crypto diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridPbkdf2Spec.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridPbkdf2Spec.hpp new file mode 100644 index 00000000..c07a2744 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridPbkdf2Spec.hpp @@ -0,0 +1,66 @@ +/// +/// HybridPbkdf2Spec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +// Forward declaration of `ArrayBuffer` to properly resolve imports. +namespace NitroModules { class ArrayBuffer; } + +#include +#include +#include +#include + +namespace margelo::nitro::crypto { + + using namespace margelo::nitro; + + /** + * An abstract base class for `Pbkdf2` + * Inherit this class to create instances of `HybridPbkdf2Spec` in C++. + * @example + * ```cpp + * class HybridPbkdf2: public HybridPbkdf2Spec { + * // ... + * }; + * ``` + */ + class HybridPbkdf2Spec: public virtual HybridObject { + public: + // Constructor + explicit HybridPbkdf2Spec(): HybridObject(TAG) { } + + // Destructor + virtual ~HybridPbkdf2Spec() { } + + public: + // Properties + virtual std::function>>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)> getPbkdf2() = 0; + virtual void setPbkdf2(const std::function>>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)>& pbkdf2) = 0; + virtual std::function>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)> getPbkdf2Sync() = 0; + virtual void setPbkdf2Sync(const std::function>(const std::shared_ptr& /* password */, const std::shared_ptr& /* salt */, double /* iterations */, double /* keylen */, const std::string& /* digest */)>& pbkdf2Sync) = 0; + + public: + // Methods + + + protected: + // Hybrid Setup + void loadHybridMethods() override; + + protected: + // Tag for logging + static constexpr auto TAG = "Pbkdf2"; + }; + +} // namespace margelo::nitro::crypto diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridRandomSpec.cpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridRandomSpec.cpp index 7a6c6cb1..559278a2 100644 --- a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridRandomSpec.cpp +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridRandomSpec.cpp @@ -1,8 +1,7 @@ /// /// HybridRandomSpec.cpp -/// Tue Aug 13 2024 /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. -/// https://github.com/mrousavy/react-native-nitro +/// https://github.com/mrousavy/nitro /// Copyright © 2024 Marc Rousavy @ Margelo /// diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridRandomSpec.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridRandomSpec.hpp index 8fdfc64a..9fb1e423 100644 --- a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridRandomSpec.hpp +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridRandomSpec.hpp @@ -1,8 +1,7 @@ /// /// HybridRandomSpec.hpp -/// Tue Aug 13 2024 /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. -/// https://github.com/mrousavy/react-native-nitro +/// https://github.com/mrousavy/nitro /// Copyright © 2024 Marc Rousavy @ Margelo /// @@ -17,6 +16,7 @@ // Forward declaration of `ArrayBuffer` to properly resolve imports. namespace NitroModules { class ArrayBuffer; } +#include #include namespace margelo::nitro::crypto { @@ -33,13 +33,13 @@ namespace margelo::nitro::crypto { * }; * ``` */ - class HybridRandomSpec: public HybridObject { + class HybridRandomSpec: public virtual HybridObject { public: // Constructor explicit HybridRandomSpec(): HybridObject(TAG) { } // Destructor - ~HybridRandomSpec() { } + virtual ~HybridRandomSpec() { } public: // Properties diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWK.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWK.hpp new file mode 100644 index 00000000..df32afeb --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWK.hpp @@ -0,0 +1,162 @@ +/// +/// JWK.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +// Forward declaration of `JWKkty` to properly resolve imports. +namespace margelo::nitro::crypto { enum class JWKkty; } +// Forward declaration of `JWKuse` to properly resolve imports. +namespace margelo::nitro::crypto { enum class JWKuse; } +// Forward declaration of `KeyUsage` to properly resolve imports. +namespace margelo::nitro::crypto { enum class KeyUsage; } + +#include +#include "JWKkty.hpp" +#include "JWKuse.hpp" +#include +#include "KeyUsage.hpp" +#include + +namespace margelo::nitro::crypto { + + /** + * A struct which can be represented as a JavaScript object (JWK). + */ + struct JWK { + public: + std::optional kty SWIFT_PRIVATE; + std::optional use SWIFT_PRIVATE; + std::optional> key_ops SWIFT_PRIVATE; + std::optional alg SWIFT_PRIVATE; + std::optional crv SWIFT_PRIVATE; + std::optional kid SWIFT_PRIVATE; + std::optional x5u SWIFT_PRIVATE; + std::optional> x5c SWIFT_PRIVATE; + std::optional x5t SWIFT_PRIVATE; + std::optional x5t_256 SWIFT_PRIVATE; + std::optional n SWIFT_PRIVATE; + std::optional e SWIFT_PRIVATE; + std::optional d SWIFT_PRIVATE; + std::optional p SWIFT_PRIVATE; + std::optional q SWIFT_PRIVATE; + std::optional x SWIFT_PRIVATE; + std::optional y SWIFT_PRIVATE; + std::optional k SWIFT_PRIVATE; + std::optional dp SWIFT_PRIVATE; + std::optional dq SWIFT_PRIVATE; + std::optional qi SWIFT_PRIVATE; + std::optional ext SWIFT_PRIVATE; + + public: + explicit JWK(std::optional kty, std::optional use, std::optional> key_ops, std::optional alg, std::optional crv, std::optional kid, std::optional x5u, std::optional> x5c, std::optional x5t, std::optional x5t_256, std::optional n, std::optional e, std::optional d, std::optional p, std::optional q, std::optional x, std::optional y, std::optional k, std::optional dp, std::optional dq, std::optional qi, std::optional ext): kty(kty), use(use), key_ops(key_ops), alg(alg), crv(crv), kid(kid), x5u(x5u), x5c(x5c), x5t(x5t), x5t_256(x5t_256), n(n), e(e), d(d), p(p), q(q), x(x), y(y), k(k), dp(dp), dq(dq), qi(qi), ext(ext) {} + }; + +} // namespace margelo::nitro::crypto + +namespace margelo::nitro { + + using namespace margelo::nitro::crypto; + + // C++ JWK <> JS JWK (object) + template <> + struct JSIConverter { + static inline JWK fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + jsi::Object obj = arg.asObject(runtime); + return JWK( + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "kty")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "use")), + JSIConverter>>::fromJSI(runtime, obj.getProperty(runtime, "key_ops")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "alg")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "crv")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "kid")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "x5u")), + JSIConverter>>::fromJSI(runtime, obj.getProperty(runtime, "x5c")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "x5t")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "x5t#256")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "n")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "e")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "d")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "p")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "q")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "x")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "y")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "k")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "dp")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "dq")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "qi")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "ext")) + ); + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, const JWK& arg) { + jsi::Object obj(runtime); + obj.setProperty(runtime, "kty", JSIConverter>::toJSI(runtime, arg.kty)); + obj.setProperty(runtime, "use", JSIConverter>::toJSI(runtime, arg.use)); + obj.setProperty(runtime, "key_ops", JSIConverter>>::toJSI(runtime, arg.key_ops)); + obj.setProperty(runtime, "alg", JSIConverter>::toJSI(runtime, arg.alg)); + obj.setProperty(runtime, "crv", JSIConverter>::toJSI(runtime, arg.crv)); + obj.setProperty(runtime, "kid", JSIConverter>::toJSI(runtime, arg.kid)); + obj.setProperty(runtime, "x5u", JSIConverter>::toJSI(runtime, arg.x5u)); + obj.setProperty(runtime, "x5c", JSIConverter>>::toJSI(runtime, arg.x5c)); + obj.setProperty(runtime, "x5t", JSIConverter>::toJSI(runtime, arg.x5t)); + obj.setProperty(runtime, "x5t#256", JSIConverter>::toJSI(runtime, arg.x5t_256)); + obj.setProperty(runtime, "n", JSIConverter>::toJSI(runtime, arg.n)); + obj.setProperty(runtime, "e", JSIConverter>::toJSI(runtime, arg.e)); + obj.setProperty(runtime, "d", JSIConverter>::toJSI(runtime, arg.d)); + obj.setProperty(runtime, "p", JSIConverter>::toJSI(runtime, arg.p)); + obj.setProperty(runtime, "q", JSIConverter>::toJSI(runtime, arg.q)); + obj.setProperty(runtime, "x", JSIConverter>::toJSI(runtime, arg.x)); + obj.setProperty(runtime, "y", JSIConverter>::toJSI(runtime, arg.y)); + obj.setProperty(runtime, "k", JSIConverter>::toJSI(runtime, arg.k)); + obj.setProperty(runtime, "dp", JSIConverter>::toJSI(runtime, arg.dp)); + obj.setProperty(runtime, "dq", JSIConverter>::toJSI(runtime, arg.dq)); + obj.setProperty(runtime, "qi", JSIConverter>::toJSI(runtime, arg.qi)); + obj.setProperty(runtime, "ext", JSIConverter>::toJSI(runtime, arg.ext)); + return obj; + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isObject()) { + return false; + } + jsi::Object obj = value.getObject(runtime); + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "kty"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "use"))) return false; + if (!JSIConverter>>::canConvert(runtime, obj.getProperty(runtime, "key_ops"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "alg"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "crv"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "kid"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "x5u"))) return false; + if (!JSIConverter>>::canConvert(runtime, obj.getProperty(runtime, "x5c"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "x5t"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "x5t#256"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "n"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "e"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "d"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "p"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "q"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "x"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "y"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "k"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "dp"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "dq"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "qi"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "ext"))) return false; + return true; + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWKkty.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWKkty.hpp new file mode 100644 index 00000000..06ec5b3b --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWKkty.hpp @@ -0,0 +1,86 @@ +/// +/// JWKkty.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::crypto { + + /** + * An enum which can be represented as a JavaScript union (JWKkty). + */ + enum class JWKkty { + AES SWIFT_NAME(aes) = 0, + RSA SWIFT_NAME(rsa) = 1, + EC SWIFT_NAME(ec) = 2, + OCT SWIFT_NAME(oct) = 3, + } CLOSED_ENUM; + +} // namespace margelo::nitro::crypto + +namespace margelo::nitro { + + using namespace margelo::nitro::crypto; + + // C++ JWKkty <> JS JWKkty (union) + template <> + struct JSIConverter { + static inline JWKkty fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + std::string unionValue = JSIConverter::fromJSI(runtime, arg); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("AES"): return JWKkty::AES; + case hashString("RSA"): return JWKkty::RSA; + case hashString("EC"): return JWKkty::EC; + case hashString("oct"): return JWKkty::OCT; + default: [[unlikely]] + throw std::runtime_error("Cannot convert \"" + unionValue + "\" to enum JWKkty - invalid value!"); + } + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, JWKkty arg) { + switch (arg) { + case JWKkty::AES: return JSIConverter::toJSI(runtime, "AES"); + case JWKkty::RSA: return JSIConverter::toJSI(runtime, "RSA"); + case JWKkty::EC: return JSIConverter::toJSI(runtime, "EC"); + case JWKkty::OCT: return JSIConverter::toJSI(runtime, "oct"); + default: [[unlikely]] + throw std::runtime_error("Cannot convert JWKkty to JS - invalid value: " + + std::to_string(static_cast(arg)) + "!"); + } + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isString()) { + return false; + } + std::string unionValue = JSIConverter::fromJSI(runtime, value); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("AES"): + case hashString("RSA"): + case hashString("EC"): + case hashString("oct"): + return true; + default: + return false; + } + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWKuse.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWKuse.hpp new file mode 100644 index 00000000..33538015 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/JWKuse.hpp @@ -0,0 +1,78 @@ +/// +/// JWKuse.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::crypto { + + /** + * An enum which can be represented as a JavaScript union (JWKuse). + */ + enum class JWKuse { + SIG SWIFT_NAME(sig) = 0, + ENC SWIFT_NAME(enc) = 1, + } CLOSED_ENUM; + +} // namespace margelo::nitro::crypto + +namespace margelo::nitro { + + using namespace margelo::nitro::crypto; + + // C++ JWKuse <> JS JWKuse (union) + template <> + struct JSIConverter { + static inline JWKuse fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + std::string unionValue = JSIConverter::fromJSI(runtime, arg); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("sig"): return JWKuse::SIG; + case hashString("enc"): return JWKuse::ENC; + default: [[unlikely]] + throw std::runtime_error("Cannot convert \"" + unionValue + "\" to enum JWKuse - invalid value!"); + } + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, JWKuse arg) { + switch (arg) { + case JWKuse::SIG: return JSIConverter::toJSI(runtime, "sig"); + case JWKuse::ENC: return JSIConverter::toJSI(runtime, "enc"); + default: [[unlikely]] + throw std::runtime_error("Cannot convert JWKuse to JS - invalid value: " + + std::to_string(static_cast(arg)) + "!"); + } + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isString()) { + return false; + } + std::string unionValue = JSIConverter::fromJSI(runtime, value); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("sig"): + case hashString("enc"): + return true; + default: + return false; + } + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KFormatType.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KFormatType.hpp new file mode 100644 index 00000000..6ebd2f87 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KFormatType.hpp @@ -0,0 +1,65 @@ +/// +/// KFormatType.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::crypto { + + /** + * An enum which can be represented as a JavaScript enum (KFormatType). + */ + enum class KFormatType { + KKEYFORMATDER SWIFT_NAME(kkeyformatder) = 0, + KKEYFORMATPEM SWIFT_NAME(kkeyformatpem) = 1, + KKEYFORMATJWK SWIFT_NAME(kkeyformatjwk) = 2, + } CLOSED_ENUM; + +} // namespace margelo::nitro::crypto + +namespace margelo::nitro { + + using namespace margelo::nitro::crypto; + + // C++ KFormatType <> JS KFormatType (enum) + template <> + struct JSIConverter { + static inline KFormatType fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + int enumValue = JSIConverter::fromJSI(runtime, arg); + return static_cast(enumValue); + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, KFormatType arg) { + int enumValue = static_cast(arg); + return JSIConverter::toJSI(runtime, enumValue); + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isNumber()) { + return false; + } + double integer; + double fraction = modf(value.getNumber(), &integer); + if (fraction != 0.0) { + // It is some kind of floating point number - our enums are ints. + return false; + } + // Check if we are within the bounds of the enum. + return integer >= 0 && integer <= 2; + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyDetail.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyDetail.hpp new file mode 100644 index 00000000..4b3d244e --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyDetail.hpp @@ -0,0 +1,93 @@ +/// +/// KeyDetail.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + + + +#include +#include + +namespace margelo::nitro::crypto { + + /** + * A struct which can be represented as a JavaScript object (KeyDetail). + */ + struct KeyDetail { + public: + std::optional length SWIFT_PRIVATE; + std::optional publicExponent SWIFT_PRIVATE; + std::optional modulusLength SWIFT_PRIVATE; + std::optional hashAlgorithm SWIFT_PRIVATE; + std::optional mgf1HashAlgorithm SWIFT_PRIVATE; + std::optional saltLength SWIFT_PRIVATE; + std::optional namedCurve SWIFT_PRIVATE; + + public: + explicit KeyDetail(std::optional length, std::optional publicExponent, std::optional modulusLength, std::optional hashAlgorithm, std::optional mgf1HashAlgorithm, std::optional saltLength, std::optional namedCurve): length(length), publicExponent(publicExponent), modulusLength(modulusLength), hashAlgorithm(hashAlgorithm), mgf1HashAlgorithm(mgf1HashAlgorithm), saltLength(saltLength), namedCurve(namedCurve) {} + }; + +} // namespace margelo::nitro::crypto + +namespace margelo::nitro { + + using namespace margelo::nitro::crypto; + + // C++ KeyDetail <> JS KeyDetail (object) + template <> + struct JSIConverter { + static inline KeyDetail fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + jsi::Object obj = arg.asObject(runtime); + return KeyDetail( + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "length")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "publicExponent")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "modulusLength")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "hashAlgorithm")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "mgf1HashAlgorithm")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "saltLength")), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, "namedCurve")) + ); + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, const KeyDetail& arg) { + jsi::Object obj(runtime); + obj.setProperty(runtime, "length", JSIConverter>::toJSI(runtime, arg.length)); + obj.setProperty(runtime, "publicExponent", JSIConverter>::toJSI(runtime, arg.publicExponent)); + obj.setProperty(runtime, "modulusLength", JSIConverter>::toJSI(runtime, arg.modulusLength)); + obj.setProperty(runtime, "hashAlgorithm", JSIConverter>::toJSI(runtime, arg.hashAlgorithm)); + obj.setProperty(runtime, "mgf1HashAlgorithm", JSIConverter>::toJSI(runtime, arg.mgf1HashAlgorithm)); + obj.setProperty(runtime, "saltLength", JSIConverter>::toJSI(runtime, arg.saltLength)); + obj.setProperty(runtime, "namedCurve", JSIConverter>::toJSI(runtime, arg.namedCurve)); + return obj; + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isObject()) { + return false; + } + jsi::Object obj = value.getObject(runtime); + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "length"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "publicExponent"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "modulusLength"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "hashAlgorithm"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "mgf1HashAlgorithm"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "saltLength"))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, "namedCurve"))) return false; + return true; + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyEncoding.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyEncoding.hpp new file mode 100644 index 00000000..13c1b5cb --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyEncoding.hpp @@ -0,0 +1,66 @@ +/// +/// KeyEncoding.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::crypto { + + /** + * An enum which can be represented as a JavaScript enum (KeyEncoding). + */ + enum class KeyEncoding { + KKEYENCODINGPKCS1 SWIFT_NAME(kkeyencodingpkcs1) = 0, + KKEYENCODINGPKCS8 SWIFT_NAME(kkeyencodingpkcs8) = 1, + KKEYENCODINGSPKI SWIFT_NAME(kkeyencodingspki) = 2, + KKEYENCODINGSEC1 SWIFT_NAME(kkeyencodingsec1) = 3, + } CLOSED_ENUM; + +} // namespace margelo::nitro::crypto + +namespace margelo::nitro { + + using namespace margelo::nitro::crypto; + + // C++ KeyEncoding <> JS KeyEncoding (enum) + template <> + struct JSIConverter { + static inline KeyEncoding fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + int enumValue = JSIConverter::fromJSI(runtime, arg); + return static_cast(enumValue); + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, KeyEncoding arg) { + int enumValue = static_cast(arg); + return JSIConverter::toJSI(runtime, enumValue); + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isNumber()) { + return false; + } + double integer; + double fraction = modf(value.getNumber(), &integer); + if (fraction != 0.0) { + // It is some kind of floating point number - our enums are ints. + return false; + } + // Check if we are within the bounds of the enum. + return integer >= 0 && integer <= 3; + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyType.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyType.hpp new file mode 100644 index 00000000..645d0535 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyType.hpp @@ -0,0 +1,65 @@ +/// +/// KeyType.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::crypto { + + /** + * An enum which can be represented as a JavaScript enum (KeyType). + */ + enum class KeyType { + SECRET SWIFT_NAME(secret) = 0, + PUBLIC SWIFT_NAME(public) = 1, + PRIVATE SWIFT_NAME(private) = 2, + } CLOSED_ENUM; + +} // namespace margelo::nitro::crypto + +namespace margelo::nitro { + + using namespace margelo::nitro::crypto; + + // C++ KeyType <> JS KeyType (enum) + template <> + struct JSIConverter { + static inline KeyType fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + int enumValue = JSIConverter::fromJSI(runtime, arg); + return static_cast(enumValue); + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, KeyType arg) { + int enumValue = static_cast(arg); + return JSIConverter::toJSI(runtime, enumValue); + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isNumber()) { + return false; + } + double integer; + double fraction = modf(value.getNumber(), &integer); + if (fraction != 0.0) { + // It is some kind of floating point number - our enums are ints. + return false; + } + // Check if we are within the bounds of the enum. + return integer >= 0 && integer <= 2; + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyUsage.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyUsage.hpp new file mode 100644 index 00000000..eba3e7e2 --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/KeyUsage.hpp @@ -0,0 +1,102 @@ +/// +/// KeyUsage.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::crypto { + + /** + * An enum which can be represented as a JavaScript union (KeyUsage). + */ + enum class KeyUsage { + ENCRYPT SWIFT_NAME(encrypt) = 0, + DECRYPT SWIFT_NAME(decrypt) = 1, + SIGN SWIFT_NAME(sign) = 2, + VERIFY SWIFT_NAME(verify) = 3, + DERIVEKEY SWIFT_NAME(derivekey) = 4, + DERIVEBITS SWIFT_NAME(derivebits) = 5, + WRAPKEY SWIFT_NAME(wrapkey) = 6, + UNWRAPKEY SWIFT_NAME(unwrapkey) = 7, + } CLOSED_ENUM; + +} // namespace margelo::nitro::crypto + +namespace margelo::nitro { + + using namespace margelo::nitro::crypto; + + // C++ KeyUsage <> JS KeyUsage (union) + template <> + struct JSIConverter { + static inline KeyUsage fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + std::string unionValue = JSIConverter::fromJSI(runtime, arg); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("encrypt"): return KeyUsage::ENCRYPT; + case hashString("decrypt"): return KeyUsage::DECRYPT; + case hashString("sign"): return KeyUsage::SIGN; + case hashString("verify"): return KeyUsage::VERIFY; + case hashString("deriveKey"): return KeyUsage::DERIVEKEY; + case hashString("deriveBits"): return KeyUsage::DERIVEBITS; + case hashString("wrapKey"): return KeyUsage::WRAPKEY; + case hashString("unwrapKey"): return KeyUsage::UNWRAPKEY; + default: [[unlikely]] + throw std::runtime_error("Cannot convert \"" + unionValue + "\" to enum KeyUsage - invalid value!"); + } + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, KeyUsage arg) { + switch (arg) { + case KeyUsage::ENCRYPT: return JSIConverter::toJSI(runtime, "encrypt"); + case KeyUsage::DECRYPT: return JSIConverter::toJSI(runtime, "decrypt"); + case KeyUsage::SIGN: return JSIConverter::toJSI(runtime, "sign"); + case KeyUsage::VERIFY: return JSIConverter::toJSI(runtime, "verify"); + case KeyUsage::DERIVEKEY: return JSIConverter::toJSI(runtime, "deriveKey"); + case KeyUsage::DERIVEBITS: return JSIConverter::toJSI(runtime, "deriveBits"); + case KeyUsage::WRAPKEY: return JSIConverter::toJSI(runtime, "wrapKey"); + case KeyUsage::UNWRAPKEY: return JSIConverter::toJSI(runtime, "unwrapKey"); + default: [[unlikely]] + throw std::runtime_error("Cannot convert KeyUsage to JS - invalid value: " + + std::to_string(static_cast(arg)) + "!"); + } + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isString()) { + return false; + } + std::string unionValue = JSIConverter::fromJSI(runtime, value); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("encrypt"): + case hashString("decrypt"): + case hashString("sign"): + case hashString("verify"): + case hashString("deriveKey"): + case hashString("deriveBits"): + case hashString("wrapKey"): + case hashString("unwrapKey"): + return true; + default: + return false; + } + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/NamedCurve.hpp b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/NamedCurve.hpp new file mode 100644 index 00000000..2d04adae --- /dev/null +++ b/packages/react-native-quick-crypto/nitrogen/generated/shared/c++/NamedCurve.hpp @@ -0,0 +1,82 @@ +/// +/// NamedCurve.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::crypto { + + /** + * An enum which can be represented as a JavaScript union (NamedCurve). + */ + enum class NamedCurve { + P_256 SWIFT_NAME(p256) = 0, + P_384 SWIFT_NAME(p384) = 1, + P_521 SWIFT_NAME(p521) = 2, + } CLOSED_ENUM; + +} // namespace margelo::nitro::crypto + +namespace margelo::nitro { + + using namespace margelo::nitro::crypto; + + // C++ NamedCurve <> JS NamedCurve (union) + template <> + struct JSIConverter { + static inline NamedCurve fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + std::string unionValue = JSIConverter::fromJSI(runtime, arg); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("P-256"): return NamedCurve::P_256; + case hashString("P-384"): return NamedCurve::P_384; + case hashString("P-521"): return NamedCurve::P_521; + default: [[unlikely]] + throw std::runtime_error("Cannot convert \"" + unionValue + "\" to enum NamedCurve - invalid value!"); + } + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, NamedCurve arg) { + switch (arg) { + case NamedCurve::P_256: return JSIConverter::toJSI(runtime, "P-256"); + case NamedCurve::P_384: return JSIConverter::toJSI(runtime, "P-384"); + case NamedCurve::P_521: return JSIConverter::toJSI(runtime, "P-521"); + default: [[unlikely]] + throw std::runtime_error("Cannot convert NamedCurve to JS - invalid value: " + + std::to_string(static_cast(arg)) + "!"); + } + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isString()) { + return false; + } + std::string unionValue = JSIConverter::fromJSI(runtime, value); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("P-256"): + case hashString("P-384"): + case hashString("P-521"): + return true; + default: + return false; + } + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-quick-crypto/package.json b/packages/react-native-quick-crypto/package.json index d7d8520f..a2e168d5 100644 --- a/packages/react-native-quick-crypto/package.json +++ b/packages/react-native-quick-crypto/package.json @@ -36,6 +36,7 @@ "format-fix": "prettier --write \"**/*.{js,ts,tsx}\"", "prepare": "bun clean && bob build", "release-it": "bun prepare && release-it", + "specs": "bun run --filter=\"**\" typescript && bun nitro-codegen --logLevel=\"debug\"", "test": "jest", "postinstall": "tsc || exit 0;" }, @@ -68,7 +69,7 @@ "dependencies": { "@craftzdog/react-native-buffer": "6.0.5", "events": "3.3.0", - "react-native-nitro-modules": "0.7.0", + "react-native-nitro-modules": "0.9.0", "react-native-quick-base64": "2.1.2", "readable-stream": "4.5.2", "string_decoder": "1.3.0", @@ -86,7 +87,7 @@ "eslint": "9.9.0", "eslint-plugin-react-native": "^4.1.0", "jest": "29.7.0", - "nitro-codegen": "0.7.0", + "nitro-codegen": "0.9.0", "prettier": "3.2.5", "react": "18.3.1", "react-native": "0.74.5", diff --git a/packages/react-native-quick-crypto/src/utils/types.ts b/packages/react-native-quick-crypto/src/utils/types.ts index 0cff7b63..db6c44f3 100644 --- a/packages/react-native-quick-crypto/src/utils/types.ts +++ b/packages/react-native-quick-crypto/src/utils/types.ts @@ -127,7 +127,7 @@ export enum KeyEncoding { kKeyEncodingSEC1, } -export type AsymmetricKeyType = 'rsa' | 'rsa-pss' | 'dsa' | 'ec' | undefined; +export type AsymmetricKeyType = 'rsa' | 'rsa-pss' | 'dsa' | 'ec'; type JWKkty = 'AES' | 'RSA' | 'EC' | 'oct'; type JWKuse = 'sig' | 'enc'; @@ -155,7 +155,7 @@ export interface JWK { dq?: string; qi?: string; ext?: boolean; -}; +} export type KTypePrivate = 'pkcs1' | 'pkcs8' | 'sec1'; export type KTypePublic = 'pkcs1' | 'spki'; @@ -180,7 +180,7 @@ export type EncodingOptions = { oaepLabel?: BinaryLike; }; -export type KeyDetail = { +export interface KeyDetail { length?: number; publicExponent?: number; modulusLength?: number; @@ -188,4 +188,4 @@ export type KeyDetail = { mgf1HashAlgorithm?: string; saltLength?: number; namedCurve?: string; -}; +} From 22a694b59b6c750b40a8f9484fac2af939b2b16a Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Mon, 16 Sep 2024 10:53:17 -0400 Subject: [PATCH 07/20] more prettier rig work --- CONTRIBUTING.md | 6 +- bun.lockb | Bin 549848 -> 549528 bytes example/index.ts | 16 +- example/jest.config.js | 2 +- example/package.json | 4 +- example/src/App.tsx | 6 +- .../benchmarks/crypto-browserify/random.ts | 14 +- example/src/benchmarks/rnqc/random.ts | 14 +- example/src/benchmarks/types.ts | 2 +- example/src/benchmarks/utils.ts | 14 +- example/src/components/BenchmarkItem.tsx | 57 ++- .../src/components/BenchmarkResultItem.tsx | 32 +- example/src/components/Button.tsx | 23 +- example/src/components/CorrectResultItem.tsx | 16 +- .../src/components/IncorrectResultItem.tsx | 22 +- example/src/components/Suite.tsx | 18 +- example/src/components/TestItem.tsx | 51 +- example/src/hooks/useBenchmarksList.ts | 100 ++-- example/src/hooks/useBenchmarksRun.ts | 64 +-- example/src/hooks/useTestsList.ts | 69 ++- example/src/hooks/useTestsRun.ts | 118 ++--- example/src/navigators/Root.tsx | 6 +- .../children/BenchmarkDetailsScreen.tsx | 29 +- .../navigators/children/BenchmarkStack.tsx | 14 +- .../children/BenchmarkSuitesScreen.tsx | 37 +- .../navigators/children/TestDetailsScreen.tsx | 49 +- example/src/navigators/children/TestStack.tsx | 14 +- .../navigators/children/TestSuitesScreen.tsx | 32 +- example/src/styles/colors.ts | 1 - example/src/testing/MochaRNAdapter.ts | 32 +- .../src/testing/tests/random/random_tests.ts | 463 +++++++++--------- example/src/testing/tests/util.ts | 29 +- example/src/types/Results.ts | 54 +- example/src/types/Suite.ts | 20 +- package.json | 4 +- .../react-native-quick-crypto/package.json | 6 +- 36 files changed, 723 insertions(+), 715 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9d5043da..b5b7fd3f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,14 +23,16 @@ bun example Make sure your code passes TypeScript and ESLint. Run the following to verify: ```sh -bun tsx +bun tsc bun lint +bun format ``` To fix formatting errors, run the following: ```sh -bun lint-fix +bun lint:fix +bun format:fix ``` Remember to add tests for your change if possible. Run the unit tests by: diff --git a/bun.lockb b/bun.lockb index 403b895d87469c64e6cf3ed2627532c42a4b31da..ec14727c446e5d4e035b24e8f031b3588758638d 100755 GIT binary patch delta 13753 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 diff --git a/example/index.ts b/example/index.ts index e2c81b82..180590ef 100644 --- a/example/index.ts +++ b/example/index.ts @@ -1,19 +1,19 @@ // polyfills -import { install } from 'react-native-quick-crypto' -install() +import { install } from 'react-native-quick-crypto'; +install(); // mocha things -global.process.cwd = () => 'sxsx' +global.process.cwd = () => 'sxsx'; // readable-stream // @ts-expect-error - although process.version is readonly, we're setting it for readable-stream -global.process.version = 'v22.0.0' +global.process.version = 'v22.0.0'; // global.process.env = { NODE_ENV: 'production' }; // global.location = {}; -import { AppRegistry } from 'react-native' -import App from './src/App' -import { name as appName } from './app.json' +import { AppRegistry } from 'react-native'; +import App from './src/App'; +import { name as appName } from './app.json'; -AppRegistry.registerComponent(appName, () => App) +AppRegistry.registerComponent(appName, () => App); diff --git a/example/jest.config.js b/example/jest.config.js index 1fbafc9c..8eb675e9 100644 --- a/example/jest.config.js +++ b/example/jest.config.js @@ -1,3 +1,3 @@ module.exports = { preset: 'react-native', -} +}; diff --git a/example/package.json b/example/package.json index ba22af1e..05d64c6e 100644 --- a/example/package.json +++ b/example/package.json @@ -10,7 +10,9 @@ "tsc": "tsc --noEmit", "typescript": "tsc --noEmit", "lint": "eslint \"**/*.{js,ts,tsx}\"", - "lint-fix": "eslint \"**/*.{js,ts,tsx}\" --fix", + "lint:fix": "eslint \"**/*.{js,ts,tsx}\" --fix", + "format": "prettier --check \"**/*.{js,ts,tsx}\"", + "format:fix": "prettier --write \"**/*.{js,ts,tsx}\"", "start": "react-native start", "pods": "cd ios && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install && rm -rf .xcode.env.local", "build:android": "cd android && ./gradlew assembleDebug --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a", diff --git a/example/src/App.tsx b/example/src/App.tsx index 581f3b4b..31d3bac6 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,6 +1,6 @@ -import * as React from 'react' -import { Root } from './navigators/Root' +import * as React from 'react'; +import { Root } from './navigators/Root'; export default function App() { - return + return ; } diff --git a/example/src/benchmarks/crypto-browserify/random.ts b/example/src/benchmarks/crypto-browserify/random.ts index b46baddf..aeb251bb 100644 --- a/example/src/benchmarks/crypto-browserify/random.ts +++ b/example/src/benchmarks/crypto-browserify/random.ts @@ -1,16 +1,16 @@ // @ts-expect-error - crypto-browserify is not typed -import { randomBytes } from 'crypto-browserify' -import type { BenchmarkFn } from '../types' +import { randomBytes } from 'crypto-browserify'; +import type { BenchmarkFn } from '../types'; const randomBytes10: BenchmarkFn = () => { - randomBytes(10) -} + randomBytes(10); +}; const randomBytes1024: BenchmarkFn = () => { - randomBytes(1024) -} + randomBytes(1024); +}; export default { randomBytes10, randomBytes1024, -} +}; diff --git a/example/src/benchmarks/rnqc/random.ts b/example/src/benchmarks/rnqc/random.ts index 28d7efb1..1cc2e08b 100644 --- a/example/src/benchmarks/rnqc/random.ts +++ b/example/src/benchmarks/rnqc/random.ts @@ -1,15 +1,15 @@ -import rnqc from 'react-native-quick-crypto' -import type { BenchmarkFn } from '../types' +import rnqc from 'react-native-quick-crypto'; +import type { BenchmarkFn } from '../types'; const randomBytes10: BenchmarkFn = () => { - rnqc.randomBytes(10) -} + rnqc.randomBytes(10); +}; const randomBytes1024: BenchmarkFn = () => { - rnqc.randomBytes(1024) -} + rnqc.randomBytes(1024); +}; export default { randomBytes10, randomBytes1024, -} +}; diff --git a/example/src/benchmarks/types.ts b/example/src/benchmarks/types.ts index 32c889e8..457f191b 100644 --- a/example/src/benchmarks/types.ts +++ b/example/src/benchmarks/types.ts @@ -1 +1 @@ -export type BenchmarkFn = () => void +export type BenchmarkFn = () => void; diff --git a/example/src/benchmarks/utils.ts b/example/src/benchmarks/utils.ts index 417ace6d..443b2759 100644 --- a/example/src/benchmarks/utils.ts +++ b/example/src/benchmarks/utils.ts @@ -1,18 +1,18 @@ -import type { BenchmarkResult } from '../types/Results' +import type { BenchmarkResult } from '../types/Results'; export const formatNumber = ( n: number, decimals: number, - suffix: string + suffix: string, ): string => { if (isNaN(n)) { - return '' + return ''; } - return n.toFixed(decimals) + suffix -} + return n.toFixed(decimals) + suffix; +}; export const calculateTimes = (result: BenchmarkResult): number => { return result.type === 'faster' ? 1 + (result.them - result.us) / result.us - : 1 + (result.us - result.them) / result.them -} + : 1 + (result.us - result.them) / result.them; +}; diff --git a/example/src/components/BenchmarkItem.tsx b/example/src/components/BenchmarkItem.tsx index a4c1311f..a241dec3 100644 --- a/example/src/components/BenchmarkItem.tsx +++ b/example/src/components/BenchmarkItem.tsx @@ -1,18 +1,18 @@ -import React from 'react' -import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' -import BouncyCheckbox from 'react-native-bouncy-checkbox' -import type { BenchmarkResult } from '../types/Results' -import { useNavigation } from '@react-navigation/native' -import { calculateTimes, formatNumber } from '../benchmarks/utils' -import { colors } from '../styles/colors' +import React from 'react'; +import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; +import BouncyCheckbox from 'react-native-bouncy-checkbox'; +import type { BenchmarkResult } from '../types/Results'; +import { useNavigation } from '@react-navigation/native'; +import { calculateTimes, formatNumber } from '../benchmarks/utils'; +import { colors } from '../styles/colors'; type BenchmarkItemProps = { - description: string - value: boolean - count: number - results: BenchmarkResult[] - onToggle: (description: string) => void -} + description: string; + value: boolean; + count: number; + results: BenchmarkResult[]; + onToggle: (description: string) => void; +}; export const BenchmarkItem: React.FC = ({ description, @@ -21,17 +21,17 @@ export const BenchmarkItem: React.FC = ({ results, onToggle, }: BenchmarkItemProps) => { - const navigation = useNavigation() + const navigation = useNavigation(); const stats = { us: 0, them: 0, - } - results.map((r) => { - stats.us += r.us - stats.them += r.them - }) - const timesType = stats.us < stats.them ? 'faster' : 'slower' - const timesStyle = timesType === 'faster' ? styles.faster : styles.slower + }; + results.map(r => { + stats.us += r.us; + stats.them += r.them; + }); + const timesType = stats.us < stats.them ? 'faster' : 'slower'; + const timesStyle = timesType === 'faster' ? styles.faster : styles.slower; const times = calculateTimes({ type: timesType, ...stats, @@ -39,14 +39,14 @@ export const BenchmarkItem: React.FC = ({ description: '', indentation: 0, suiteName: '', - }) + }); return ( { - onToggle(description) + onToggle(description); }} disableText={true} fillColor={colors.blue} @@ -59,9 +59,8 @@ export const BenchmarkItem: React.FC = ({ navigation.navigate('BenchmarkDetailsScreen', { results, suiteName: description, - }) - }} - > + }); + }}> {description} @@ -73,8 +72,8 @@ export const BenchmarkItem: React.FC = ({ - ) -} + ); +}; const styles = StyleSheet.create({ container: { @@ -117,4 +116,4 @@ const styles = StyleSheet.create({ flex: 1, textAlign: 'right', }, -}) +}); diff --git a/example/src/components/BenchmarkResultItem.tsx b/example/src/components/BenchmarkResultItem.tsx index 74c640a9..81d7de96 100644 --- a/example/src/components/BenchmarkResultItem.tsx +++ b/example/src/components/BenchmarkResultItem.tsx @@ -1,12 +1,12 @@ -import React from 'react' -import { View, Text, StyleSheet } from 'react-native' -import type { BenchmarkResult } from '../types/Results' -import { calculateTimes, formatNumber } from '../benchmarks/utils' -import { colors } from '../styles/colors' +import React from 'react'; +import { View, Text, StyleSheet } from 'react-native'; +import type { BenchmarkResult } from '../types/Results'; +import { calculateTimes, formatNumber } from '../benchmarks/utils'; +import { colors } from '../styles/colors'; type BenchmarkResultItemProps = { - result: BenchmarkResult -} + result: BenchmarkResult; +}; export const BenchmarkResultItemHeader: React.FC = () => { return ( @@ -17,16 +17,16 @@ export const BenchmarkResultItemHeader: React.FC = () => { rnqc challenger - ) -} + ); +}; export const BenchmarkResultItem: React.FC = ({ result, }: BenchmarkResultItemProps) => { - const emoji = result.type === 'faster' ? '🐇' : '🐢' - const times = calculateTimes(result) - const timesType = result.type === 'faster' ? 'faster' : 'slower' - const timesStyle = timesType === 'faster' ? styles.faster : styles.slower + const emoji = result.type === 'faster' ? '🐇' : '🐢'; + const times = calculateTimes(result); + const timesType = result.type === 'faster' ? 'faster' : 'slower'; + const timesStyle = timesType === 'faster' ? styles.faster : styles.slower; return ( @@ -40,8 +40,8 @@ export const BenchmarkResultItem: React.FC = ({ {formatNumber(result.us, 2, 'ms')} {formatNumber(result.them, 2, 'ms')} - ) -} + ); +}; const styles = StyleSheet.create({ itemContainer: { @@ -77,4 +77,4 @@ const styles = StyleSheet.create({ color: colors.red, fontWeight: 'bold', }, -}) +}); diff --git a/example/src/components/Button.tsx b/example/src/components/Button.tsx index 18ce2076..a7d7541d 100644 --- a/example/src/components/Button.tsx +++ b/example/src/components/Button.tsx @@ -1,12 +1,12 @@ -import React from 'react' -import { View, Text, TouchableOpacity, StyleSheet } from 'react-native' -import { colors } from '../styles/colors' +import React from 'react'; +import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'; +import { colors } from '../styles/colors'; type ButtonProps = { - title: string - onPress: () => void - color?: string -} + title: string; + onPress: () => void; + color?: string; +}; export const Button: React.FC = ({ title, @@ -17,13 +17,12 @@ export const Button: React.FC = ({ + onPress={onPress}> {title} - ) -} + ); +}; const styles = StyleSheet.create({ container: { @@ -37,4 +36,4 @@ const styles = StyleSheet.create({ color: colors.white, alignSelf: 'center', }, -}) +}); diff --git a/example/src/components/CorrectResultItem.tsx b/example/src/components/CorrectResultItem.tsx index 78b563f8..ffdbc942 100644 --- a/example/src/components/CorrectResultItem.tsx +++ b/example/src/components/CorrectResultItem.tsx @@ -1,22 +1,22 @@ -import React from 'react' -import { View, Text, StyleSheet } from 'react-native' +import React from 'react'; +import { View, Text, StyleSheet } from 'react-native'; type CorrectResultItemProps = { - description: string -} + description: string; +}; export const CorrectResultItem: React.FC = ({ description, }: CorrectResultItemProps) => { - const emoji = '✅' + const emoji = '✅'; return ( {emoji} {description} - ) -} + ); +}; const styles = StyleSheet.create({ itemContainer: { @@ -29,4 +29,4 @@ const styles = StyleSheet.create({ fontSize: 9, paddingRight: 5, }, -}) +}); diff --git a/example/src/components/IncorrectResultItem.tsx b/example/src/components/IncorrectResultItem.tsx index 51b46db9..b08155cf 100644 --- a/example/src/components/IncorrectResultItem.tsx +++ b/example/src/components/IncorrectResultItem.tsx @@ -1,26 +1,26 @@ -import React from 'react' -import { View, Text, StyleSheet } from 'react-native' -import { colors } from '../styles/colors' +import React from 'react'; +import { View, Text, StyleSheet } from 'react-native'; +import { colors } from '../styles/colors'; type IncorrectResultItemProps = { - description: string - errorMsg: string -} + description: string; + errorMsg: string; +}; export const IncorrectResultItem: React.FC = ({ description, errorMsg, }: IncorrectResultItemProps) => { - const emoji = '❌' - const title = emoji + ' [' + description + ']' + const emoji = '❌'; + const title = emoji + ' [' + description + ']'; return ( {title} {errorMsg} - ) -} + ); +}; const styles = StyleSheet.create({ itemContainer: { @@ -35,4 +35,4 @@ const styles = StyleSheet.create({ error: { color: colors.red, }, -}) +}); diff --git a/example/src/components/Suite.tsx b/example/src/components/Suite.tsx index 1800f397..ac343e27 100644 --- a/example/src/components/Suite.tsx +++ b/example/src/components/Suite.tsx @@ -1,20 +1,20 @@ -import React from 'react' -import { View, Text, StyleSheet } from 'react-native' +import React from 'react'; +import { View, Text, StyleSheet } from 'react-native'; type SuiteProps = { - description: string -} + description: string; +}; export const Suite: React.FC = ({ description }: SuiteProps) => { - const emoji = '↘️ ' - const fullText = emoji + description + const emoji = '↘️ '; + const fullText = emoji + description; return ( {fullText} - ) -} + ); +}; const styles = StyleSheet.create({ itemContainer: { @@ -27,4 +27,4 @@ const styles = StyleSheet.create({ text: { flexShrink: 1, }, -}) +}); diff --git a/example/src/components/TestItem.tsx b/example/src/components/TestItem.tsx index 71dbb6c2..ec0827c7 100644 --- a/example/src/components/TestItem.tsx +++ b/example/src/components/TestItem.tsx @@ -1,17 +1,17 @@ -import React from 'react' -import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' -import BouncyCheckbox from 'react-native-bouncy-checkbox' -import type { TestResult } from '../types/Results' -import { useNavigation } from '@react-navigation/native' -import { colors } from '../styles/colors' +import React from 'react'; +import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; +import BouncyCheckbox from 'react-native-bouncy-checkbox'; +import type { TestResult } from '../types/Results'; +import { useNavigation } from '@react-navigation/native'; +import { colors } from '../styles/colors'; type TestItemProps = { - description: string - value: boolean - count: number - results: TestResult[] - onToggle: (description: string) => void -} + description: string; + value: boolean; + count: number; + results: TestResult[]; + onToggle: (description: string) => void; +}; export const TestItem: React.FC = ({ description, @@ -20,26 +20,26 @@ export const TestItem: React.FC = ({ results, onToggle, }: TestItemProps) => { - const navigation = useNavigation() + const navigation = useNavigation(); // get pass/fail stats from results - let pass = 0 - let fail = 0 - results.map((r) => { + let pass = 0; + let fail = 0; + results.map(r => { if (r.type === 'correct') { - pass++ + pass++; } if (r.type === 'incorrect') { - fail++ + fail++; } - }) + }); return ( { - onToggle(description) + onToggle(description); }} disableText={true} fillColor={colors.blue} @@ -52,9 +52,8 @@ export const TestItem: React.FC = ({ navigation.navigate('TestDetailsScreen', { results, suiteName: description, - }) - }} - > + }); + }}> {description} @@ -69,8 +68,8 @@ export const TestItem: React.FC = ({ - ) -} + ); +}; const styles = StyleSheet.create({ container: { @@ -107,4 +106,4 @@ const styles = StyleSheet.create({ flex: 1, textAlign: 'right', }, -}) +}); diff --git a/example/src/hooks/useBenchmarksList.ts b/example/src/hooks/useBenchmarksList.ts index 5de0ff40..21b00e75 100644 --- a/example/src/hooks/useBenchmarksList.ts +++ b/example/src/hooks/useBenchmarksList.ts @@ -1,9 +1,9 @@ -import { useCallback, useState } from 'react' -import type { Benchmark, BenchmarkSuite, Suites } from '../types/Suite' -import type { BenchmarkFn } from '../benchmarks/types' +import { useCallback, useState } from 'react'; +import type { Benchmark, BenchmarkSuite, Suites } from '../types/Suite'; +import type { BenchmarkFn } from '../benchmarks/types'; export const useBenchmarksList = ( - challenger: string + challenger: string, ): [ Suites, (description: string) => void, @@ -11,75 +11,75 @@ export const useBenchmarksList = ( () => void, ] => { const [suites, setSuites] = useState>( - getInitialSuites(challenger) - ) + getInitialSuites(challenger), + ); const toggle = useCallback( (description: string) => { - setSuites((tests) => { - tests[description]!.value = !tests[description]!.value - return tests - }) + setSuites(tests => { + tests[description]!.value = !tests[description]!.value; + return tests; + }); }, - [setSuites] - ) + [setSuites], + ); const clearAll = useCallback(() => { - setSuites((prev) => { - Object.values(prev).forEach((suite) => { - suite.value = false - }) - return { ...prev } - }) - }, [setSuites]) + setSuites(prev => { + Object.values(prev).forEach(suite => { + suite.value = false; + }); + return { ...prev }; + }); + }, [setSuites]); const checkAll = useCallback(() => { - setSuites((prev) => { - Object.values(prev).forEach((suite) => { - suite.value = true - }) - return { ...prev } - }) - }, [setSuites]) + setSuites(prev => { + Object.values(prev).forEach(suite => { + suite.value = true; + }); + return { ...prev }; + }); + }, [setSuites]); - return [suites, toggle, clearAll, checkAll] -} + return [suites, toggle, clearAll, checkAll]; +}; const getInitialSuites = (challenger: string) => { const suiteNames: string[] = [ // random - all challengers use `crypto` too,so the comparison is to 'us' - maybe skip in future 'random', - ] - const suites: Suites = {} - suiteNames.forEach((suiteName) => { - const benchmarks = loadBenchmarks(suiteName, challenger) - suites[suiteName] = { value: false, count: benchmarks.length, benchmarks } - }) + ]; + const suites: Suites = {}; + suiteNames.forEach(suiteName => { + const benchmarks = loadBenchmarks(suiteName, challenger); + suites[suiteName] = { value: false, count: benchmarks.length, benchmarks }; + }); // return count-enhanced list and totals - return suites -} + return suites; +}; const loadBenchmarks = (suiteName: string, challenger: string): Benchmark[] => { - const us = allBenchmarks[`rnqc/${suiteName}`] - const them = allBenchmarks[`${challenger}/${suiteName}`] + const us = allBenchmarks[`rnqc/${suiteName}`]; + const them = allBenchmarks[`${challenger}/${suiteName}`]; if (!us || !them) { - throw new Error(`Could not load benchmarks for ${suiteName}`) + throw new Error(`Could not load benchmarks for ${suiteName}`); } - const ret: Benchmark[] = [] - const themKeys = Object.keys(them) + const ret: Benchmark[] = []; + const themKeys = Object.keys(them); // add all 'us' benchmarks Object.entries(us).forEach(([name, fn]) => { - ret.push({ name, us: fn, them: them[name] }) + ret.push({ name, us: fn, them: them[name] }); // remove from themKeys - themKeys.splice(themKeys.indexOf(name), 1) - }) + themKeys.splice(themKeys.indexOf(name), 1); + }); // add all 'them' benchmarks that are not in 'us' - themKeys.forEach((name) => { - ret.push({ name, us: us[name], them: them[name] }) - }) - return ret -} + themKeys.forEach(name => { + ret.push({ name, us: us[name], them: them[name] }); + }); + return ret; +}; // can't use dynamic strings here, as require() is compile-time /* eslint-disable @typescript-eslint/no-require-imports */ @@ -87,4 +87,4 @@ const allBenchmarks: Record> = { 'rnqc/random': require('../benchmarks/rnqc/random').default, 'crypto-browserify/random': require('../benchmarks/crypto-browserify/random') .default, -} +}; diff --git a/example/src/hooks/useBenchmarksRun.ts b/example/src/hooks/useBenchmarksRun.ts index 0e6857b9..ee3980ee 100644 --- a/example/src/hooks/useBenchmarksRun.ts +++ b/example/src/hooks/useBenchmarksRun.ts @@ -1,49 +1,49 @@ -import { useCallback, useState } from 'react' -import type { BenchmarkSuite, Suites } from '../types/Suite' -import type { SuiteResults, BenchmarkResult } from '../types/Results' +import { useCallback, useState } from 'react'; +import type { BenchmarkSuite, Suites } from '../types/Suite'; +import type { SuiteResults, BenchmarkResult } from '../types/Results'; export const useBenchmarksRun = ( - runCount: number + runCount: number, ): [ SuiteResults, (suites: Suites) => void, ] => { - const [results, setResults] = useState>({}) + const [results, setResults] = useState>({}); const addResult = useCallback( (newResult: BenchmarkResult) => { - setResults((prev) => { + setResults(prev => { if (!prev[newResult.suiteName]) { - prev[newResult.suiteName] = { results: [] } + prev[newResult.suiteName] = { results: [] }; } - prev[newResult.suiteName]?.results.push(newResult) - return { ...prev } - }) + prev[newResult.suiteName]?.results.push(newResult); + return { ...prev }; + }); }, - [setResults] - ) + [setResults], + ); const runBenchmarks = (suites: Suites) => { - setResults({}) - run(addResult, suites, runCount) - } + setResults({}); + run(addResult, suites, runCount); + }; - return [results, runBenchmarks] -} + return [results, runBenchmarks]; +}; const run = ( addBenchmarkResult: (benchmarkResult: BenchmarkResult) => void, suites: Suites = {}, - runCount: number + runCount: number, ) => { Object.entries(suites).forEach(([suiteName, suite]) => { if (suite.value) { - suite.benchmarks.map((benchmark) => { + suite.benchmarks.map(benchmark => { if (!benchmark.them || !benchmark.us) { - return + return; } - const them = runBenchmark(benchmark.them, runCount) - const us = runBenchmark(benchmark.us, runCount) + const them = runBenchmark(benchmark.them, runCount); + const us = runBenchmark(benchmark.us, runCount); addBenchmarkResult({ indentation: 0, description: benchmark.name, @@ -51,22 +51,22 @@ const run = ( us, them, type: us < them ? 'faster' : 'slower', - }) - }) + }); + }); } - }) -} + }); +}; // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type const runBenchmark = (fn: Function, runCount: number): number => { // warm up imports, etc. - fn() + fn(); // do the actual benchmark - const start = performance.now() + const start = performance.now(); for (let i = 0; i < runCount; i++) { - fn() + fn(); } - const end = performance.now() - return end - start -} + const end = performance.now(); + return end - start; +}; diff --git a/example/src/hooks/useTestsList.ts b/example/src/hooks/useTestsList.ts index 19dff9b4..58d94f1b 100644 --- a/example/src/hooks/useTestsList.ts +++ b/example/src/hooks/useTestsList.ts @@ -1,10 +1,9 @@ - -import { useState, useCallback } from 'react' -import type { Suites, TestSuite } from '../types/Suite' -import { rootSuite } from '../testing/MochaRNAdapter' +import { useState, useCallback } from 'react'; +import type { Suites, TestSuite } from '../types/Suite'; +import { rootSuite } from '../testing/MochaRNAdapter'; // import '../testing/tests/pbkdf2Tests/pbkdf2Tests'; -import '../testing/tests/random/random_tests' +import '../testing/tests/random/random_tests'; // import '../testing/tests/HmacTests/HmacTests'; // import '../testing/tests/HashTests/HashTests'; // import '../testing/tests/CipherTests/CipherTestFirst'; @@ -29,48 +28,48 @@ export const useTestsList = (): [ () => void, () => void, ] => { - const [suites, setSuites] = useState>(getInitialSuites()) + const [suites, setSuites] = useState>(getInitialSuites()); const toggle = useCallback( (description: string) => { - setSuites((tests) => { - tests[description]!.value = !tests[description]!.value - return tests - }) + setSuites(tests => { + tests[description]!.value = !tests[description]!.value; + return tests; + }); }, - [setSuites] - ) + [setSuites], + ); const clearAll = useCallback(() => { - setSuites((suites) => { - Object.values(suites).forEach((suite) => { - suite.value = false - }) - return { ...suites } - }) - }, [setSuites]) + setSuites(suites => { + Object.values(suites).forEach(suite => { + suite.value = false; + }); + return { ...suites }; + }); + }, [setSuites]); const checkAll = useCallback(() => { - setSuites((suites) => { - Object.values(suites).forEach((suite) => { - suite.value = true - }) - return { ...suites } - }) - }, [setSuites]) + setSuites(suites => { + Object.values(suites).forEach(suite => { + suite.value = true; + }); + return { ...suites }; + }); + }, [setSuites]); - return [suites, toggle, clearAll, checkAll] -} + return [suites, toggle, clearAll, checkAll]; +}; const getInitialSuites = () => { - const suites: Suites = {} + const suites: Suites = {}; // interrogate the loaded mocha suites/tests via a temporary runner - const runner = new Mocha.Runner(rootSuite) - runner.suite.suites.map((s) => { - suites[s.title] = { value: false, count: s.total() } - }) + const runner = new Mocha.Runner(rootSuite); + runner.suite.suites.map(s => { + suites[s.title] = { value: false, count: s.total() }; + }); // return count-enhanced list and totals - return suites -} + return suites; +}; diff --git a/example/src/hooks/useTestsRun.ts b/example/src/hooks/useTestsRun.ts index 30d221fd..e93d187c 100644 --- a/example/src/hooks/useTestsRun.ts +++ b/example/src/hooks/useTestsRun.ts @@ -1,9 +1,9 @@ -import 'mocha' -import type * as MochaTypes from 'mocha' -import { useCallback, useState } from 'react' -import type { Suites, TestSuite } from '../types/Suite' -import type { Stats, SuiteResults, TestResult } from '../types/Results' -import { rootSuite } from '../testing/MochaRNAdapter' +import 'mocha'; +import type * as MochaTypes from 'mocha'; +import { useCallback, useState } from 'react'; +import type { Suites, TestSuite } from '../types/Suite'; +import type { Stats, SuiteResults, TestResult } from '../types/Results'; +import { rootSuite } from '../testing/MochaRNAdapter'; const defaultStats = { start: new Date(), @@ -14,38 +14,38 @@ const defaultStats = { passes: 0, pending: 0, failures: 0, -} +}; export const useTestsRun = (): [ SuiteResults, (suites: Suites) => void, ] => { - const [results, setResults] = useState>({}) + const [results, setResults] = useState>({}); const addResult = useCallback( (newResult: TestResult) => { - setResults((prev) => { + setResults(prev => { if (!prev[newResult.suiteName]) { - prev[newResult.suiteName] = { results: [] } + prev[newResult.suiteName] = { results: [] }; } - prev[newResult.suiteName]?.results.push(newResult) - return { ...prev } - }) + prev[newResult.suiteName]?.results.push(newResult); + return { ...prev }; + }); }, - [setResults] - ) + [setResults], + ); const runTests = (suites: Suites) => { - setResults({}) - run(addResult, suites) - } + setResults({}); + run(addResult, suites); + }; - return [results, runTests] -} + return [results, runTests]; +}; const run = ( addTestResult: (testResult: TestResult) => void, - tests: Suites = {} + tests: Suites = {}, ) => { const { EVENT_RUN_BEGIN, @@ -56,82 +56,82 @@ const run = ( EVENT_TEST_END, EVENT_SUITE_BEGIN, EVENT_SUITE_END, - } = Mocha.Runner.constants + } = Mocha.Runner.constants; - const stats: Stats = { ...defaultStats } + const stats: Stats = { ...defaultStats }; - const runner = new Mocha.Runner(rootSuite) - runner.stats = stats + const runner = new Mocha.Runner(rootSuite); + runner.stats = stats; // enable/disable tests based on checkbox value - runner.suite.suites.map((s) => { - const suiteName = s.title + runner.suite.suites.map(s => { + const suiteName = s.title; if (!tests[suiteName]?.value) { // console.log(`skipping '${suiteName}' suite`); - s.tests.map((t) => { - t.skip() - }) + s.tests.map(t => { + t.skip(); + }); } else { // console.log(`will run '${suiteName}' suite`); - s.tests.map((t) => { + s.tests.map(t => { // @ts-expect-error - not sure why this is erroring - t.reset() - }) + t.reset(); + }); } - }) + }); - let indents = -1 - const indent = () => Array(indents).join(' ') + let indents = -1; + const indent = () => Array(indents).join(' '); runner .once(EVENT_RUN_BEGIN, () => { - stats.start = new Date() + stats.start = new Date(); }) .on(EVENT_SUITE_BEGIN, (suite: MochaTypes.Suite) => { - if (!suite.root) stats.suites++ - indents++ + if (!suite.root) stats.suites++; + indents++; }) .on(EVENT_SUITE_END, () => { - indents-- + indents--; }) .on(EVENT_TEST_PASS, (test: MochaTypes.Runnable) => { - const name = test.parent?.title || '' - stats.passes++ + const name = test.parent?.title || ''; + stats.passes++; addTestResult({ indentation: indents, description: test.title, suiteName: name, type: 'correct', - }) - console.log(`${indent()}pass: ${test.title}`) + }); + console.log(`${indent()}pass: ${test.title}`); }) .on(EVENT_TEST_FAIL, (test: MochaTypes.Runnable, err: Error) => { - const name = test.parent?.title || '' - stats.failures++ + const name = test.parent?.title || ''; + stats.failures++; addTestResult({ indentation: indents, description: test.title, suiteName: name, type: 'incorrect', errorMsg: err.message, - }) - console.log(`${indent()}fail: ${test.title} - error: ${err.message}`) + }); + console.log(`${indent()}fail: ${test.title} - error: ${err.message}`); }) .on(EVENT_TEST_PENDING, function () { - stats.pending++ + stats.pending++; }) .on(EVENT_TEST_END, function () { - stats.tests++ + stats.tests++; }) .once(EVENT_RUN_END, () => { - stats.end = new Date() - stats.duration = stats.end.valueOf() - stats.start.valueOf() - console.log(JSON.stringify(runner.stats, null, 2)) - }) + stats.end = new Date(); + stats.duration = stats.end.valueOf() - stats.start.valueOf(); + console.log(JSON.stringify(runner.stats, null, 2)); + }); - runner.run() + runner.run(); return () => { - console.log('aborting') - runner.abort() - } -} + console.log('aborting'); + runner.abort(); + }; +}; diff --git a/example/src/navigators/Root.tsx b/example/src/navigators/Root.tsx index 12b5291d..4a3b547a 100644 --- a/example/src/navigators/Root.tsx +++ b/example/src/navigators/Root.tsx @@ -6,7 +6,7 @@ import { BenchmarkStack } from './children/BenchmarkStack'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; -enableFreeze(true) +enableFreeze(true); const Tab = createBottomTabNavigator(); export const Root: React.FC = () => { @@ -35,5 +35,5 @@ export const Root: React.FC = () => { /> - ) -} + ); +}; diff --git a/example/src/navigators/children/BenchmarkDetailsScreen.tsx b/example/src/navigators/children/BenchmarkDetailsScreen.tsx index 488280f3..a92219f3 100644 --- a/example/src/navigators/children/BenchmarkDetailsScreen.tsx +++ b/example/src/navigators/children/BenchmarkDetailsScreen.tsx @@ -1,23 +1,23 @@ -import React from 'react' -import { SafeAreaView, ScrollView, StyleSheet, Text, View } from 'react-native' +import React from 'react'; +import { SafeAreaView, ScrollView, StyleSheet, Text, View } from 'react-native'; import { BenchmarkResultItem, BenchmarkResultItemHeader, -} from '../../components/BenchmarkResultItem' -import type { BenchmarkResult } from '../../types/Results' +} from '../../components/BenchmarkResultItem'; +import type { BenchmarkResult } from '../../types/Results'; // @ts-expect-error - not dealing with navigation types rn -type BenchmarkDetailsScreenProps = { route } +type BenchmarkDetailsScreenProps = { route }; type RouteParams = { - results: BenchmarkResult[] - suiteName: string -} + results: BenchmarkResult[]; + suiteName: string; +}; export const BenchmarkDetailsScreen = ({ route, }: BenchmarkDetailsScreenProps) => { - const { results, suiteName }: RouteParams = route.params + const { results, suiteName }: RouteParams = route.params; return ( @@ -29,15 +29,14 @@ export const BenchmarkDetailsScreen = ({ + contentContainerStyle={styles.scrollContent}> {results.map((it, index: number) => { - return + return ; })} - ) -} + ); +}; const styles = StyleSheet.create({ container: { @@ -54,4 +53,4 @@ const styles = StyleSheet.create({ scrollContent: { paddingHorizontal: 5, }, -}) +}); diff --git a/example/src/navigators/children/BenchmarkStack.tsx b/example/src/navigators/children/BenchmarkStack.tsx index 8af704a8..5e7fa535 100644 --- a/example/src/navigators/children/BenchmarkStack.tsx +++ b/example/src/navigators/children/BenchmarkStack.tsx @@ -1,9 +1,9 @@ -import React from 'react' -import { createNativeStackNavigator } from '@react-navigation/native-stack' -import { BenchmarkSuitesScreen } from './BenchmarkSuitesScreen' -import { BenchmarkDetailsScreen } from './BenchmarkDetailsScreen' +import React from 'react'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; +import { BenchmarkSuitesScreen } from './BenchmarkSuitesScreen'; +import { BenchmarkDetailsScreen } from './BenchmarkDetailsScreen'; -const Stack = createNativeStackNavigator() +const Stack = createNativeStackNavigator(); export const BenchmarkStack = () => { return ( @@ -19,5 +19,5 @@ export const BenchmarkStack = () => { options={{ title: 'Benchmark Details' }} /> - ) -} + ); +}; diff --git a/example/src/navigators/children/BenchmarkSuitesScreen.tsx b/example/src/navigators/children/BenchmarkSuitesScreen.tsx index 2612ec30..f46ede2d 100644 --- a/example/src/navigators/children/BenchmarkSuitesScreen.tsx +++ b/example/src/navigators/children/BenchmarkSuitesScreen.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useState } from 'react'; import { View, Text, @@ -6,19 +6,20 @@ import { SafeAreaView, ScrollView, TextInput, -} from 'react-native' -import { Button } from '../../components/Button' -import { BenchmarkItem } from '../../components/BenchmarkItem' -import { useBenchmarksList } from '../../hooks/useBenchmarksList' -import { useBenchmarksRun } from '../../hooks/useBenchmarksRun' -import { colors } from '../../styles/colors' +} from 'react-native'; +import { Button } from '../../components/Button'; +import { BenchmarkItem } from '../../components/BenchmarkItem'; +import { useBenchmarksList } from '../../hooks/useBenchmarksList'; +import { useBenchmarksRun } from '../../hooks/useBenchmarksRun'; +import { colors } from '../../styles/colors'; export const BenchmarkSuitesScreen = () => { - const [runCount, setRunCount] = useState(1000) - const [challenger, setChallenger] = useState('crypto-browserify') - const [benchmarks, toggle, clearAll, checkAll] = useBenchmarksList(challenger) - const [results, runBenchmarks] = useBenchmarksRun(runCount) - let totalCount = 0 + const [runCount, setRunCount] = useState(1000); + const [challenger, setChallenger] = useState('crypto-browserify'); + const [benchmarks, toggle, clearAll, checkAll] = + useBenchmarksList(challenger); + const [results, runBenchmarks] = useBenchmarksRun(runCount); + let totalCount = 0; return ( @@ -38,7 +39,7 @@ export const BenchmarkSuitesScreen = () => { {Object.entries(benchmarks).map(([suiteName, suite], index) => { - totalCount += suite.count + totalCount += suite.count; return ( { results={results[suiteName]?.results || []} onToggle={toggle} /> - ) + ); })} @@ -61,14 +62,14 @@ export const BenchmarkSuitesScreen = () => {