From 32170ba6f48097742e3cd9efc3d621afdc531d8c Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sat, 26 Jul 2025 16:27:39 -0700 Subject: [PATCH] Add CryptoKey to accepted worker data types. Fix passkey worker. --- src/lib/workers/passkey.ts | 54 ++++++++++++++++++++------------------ src/types.d.ts | 2 +- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/lib/workers/passkey.ts b/src/lib/workers/passkey.ts index 80c9f54..baf0e4a 100644 --- a/src/lib/workers/passkey.ts +++ b/src/lib/workers/passkey.ts @@ -17,21 +17,43 @@ export class Passkey extends WorkerInterface { this.listen() } - static async work (data: NamedData): Promise> { - this.#validate(data) + static async work (data: NamedData | unknown): Promise { + let method, password, salt + if (data == null) { + throw new TypeError('Worker received no data') + } + if (typeof data !== 'object') { + throw new Error('Invalid data') + } + const dataObject = data as { [key: string]: unknown } + if (!('password' in dataObject) || !(dataObject.password instanceof ArrayBuffer)) { + throw new TypeError('Password must be ArrayBuffer') + } + password = dataObject.password + if (!('method' in dataObject)) { + throw new TypeError('Method is required') + } + if (dataObject.method !== 'encrypt' && dataObject.method !== 'decrypt') { + throw new TypeError('Invalid method') + } + method = dataObject.method as typeof dataObject.method + if (method === 'decrypt') { + if (!('salt' in dataObject) || !(dataObject.salt instanceof ArrayBuffer)) { + throw new TypeError('Salt required for decryption key') + } + salt = dataObject.salt + } try { - const salt = (method === 'decrypt') - ? data.salt - : (await Entropy.create()).buffer + salt ??= (await Entropy.create()).buffer const key = await this.#createAesKey(method, password, salt) return { salt, key } } catch (err) { throw new Error('Failed to derive key from password', { cause: err }) } finally { password.transfer() - } + } } - + static async #createAesKey (purpose: 'encrypt' | 'decrypt', password: ArrayBuffer, salt: ArrayBuffer): Promise { const derivationKey = await globalThis.crypto.subtle.importKey('raw', password, 'PBKDF2', false, ['deriveBits', 'deriveKey']) const derivationAlgorithm: Pbkdf2Params = { @@ -46,24 +68,6 @@ export class Passkey extends WorkerInterface { } return await globalThis.crypto.subtle.deriveKey(derivationAlgorithm, derivationKey, derivedKeyType, false, [purpose]) } - - static #validate (data: unknown): asserts data is NamedData } { - if (data == null) { - throw new TypeError('Worker received no data') - } - if (typeof data !== 'object') { - throw new Error('Invalid data') - } - const dataObject = data as { [key: string]: unknown } - if (!(data.password instanceof ArrayBuffer)) { - throw new TypeError('Password must be ArrayBuffer') - } - if (data.method !== 'encrypt' && data.method !== 'decrypt') { - throw new TypeError('Invalid method') - } - if (data.method === 'decrypt' && !(data.salt instanceof ArrayBuffer)) { - throw new TypeError('Salt required for decryption key') - } } let importWorkerThreads = '' diff --git a/src/types.d.ts b/src/types.d.ts index 636e1b2..3bf50bf 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -377,7 +377,7 @@ export declare class ChangeBlock extends Block { constructor (account: Account | string, balance: string, representative: Account | string, frontier: string, work?: string) } -export type Data = boolean | number[] | string | ArrayBuffer +export type Data = boolean | number[] | string | ArrayBuffer | CryptoKey /** * Represents a cryptographically strong source of entropy suitable for use in -- 2.47.3