From 3648da8795d341363e2840957b32a00fdea4d1c5 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Mon, 13 Oct 2025 01:18:16 -0700 Subject: [PATCH] Deprecate NamedData type which is redundant against the built-in Record type. Clear passwords prior to awaiting promises that use them. Reduce object property lookups by using values() instead of keys(). Insert Ledger wallets to IndexedDB with zero-length buffers for encryption data. --- src/lib/database.ts | 28 ++++++++++++------------- src/lib/rolodex.ts | 18 +++++++--------- src/lib/vault/index.ts | 13 ++++++------ src/lib/vault/vault-worker.ts | 33 ++++++++++++++--------------- src/lib/wallet/backup.ts | 13 ++++-------- src/lib/wallet/create.ts | 32 ++++++++++++++-------------- src/lib/wallet/get.ts | 21 ++++++++----------- src/lib/wallet/index.ts | 21 ++++++++++++------- src/lib/wallet/load.ts | 10 +++++---- src/lib/wallet/unlock.ts | 39 +++++++++++++++++------------------ src/lib/wallet/update.ts | 24 ++++++++++----------- src/types.d.ts | 8 ------- 12 files changed, 122 insertions(+), 138 deletions(-) delete mode 100644 src/types.d.ts diff --git a/src/lib/database.ts b/src/lib/database.ts index b6a7ef4..a365c83 100644 --- a/src/lib/database.ts +++ b/src/lib/database.ts @@ -1,7 +1,7 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { Data, NamedData } from '#types' +export type Data = boolean | number | number[] | string | string[] | ArrayBuffer | CryptoKey /** * Encrypts and stores data in the browser using IndexedDB. @@ -20,11 +20,11 @@ export class Database { /** * Inserts records in a datastore, throwing if they already exist. * - * @param {NamedData} data - Object of key-value pairs + * @param {Record>} data - Object of key-value pairs * @param {string} store - Datastore in which to put records * @returns {Promise<(IDBValidKey | DOMException)[]>} Index keys of the records inserted */ - static async add (data: NamedData, store: string): Promise<(IDBValidKey | DOMException)[]> { + static async add> (data: Record, store: string): Promise<(IDBValidKey | DOMException)[]> { this.#storage ??= await this.#open(this.DB_NAME) const transaction = this.#storage.transaction(store, 'readwrite') const db = transaction.objectStore(store) @@ -88,18 +88,18 @@ export class Database { * * @param {string} name - Index key of the record to get * @param {string} store - Datastore from which to get the record - * @returns {Promise} Object of key-value pairs + * @returns {Promise>>} Object of key-value pairs */ - static async get (id: string, store: string): Promise> + static async get> (id: string, store: string): Promise> /** * Gets specific records from a datastore. * * @param {string[]} names - Index keys of the records to get * @param {string} store - Datastore from which to get records - * @returns {Promise} Object of key-value pairs + * @returns {Promise>>} Object of key-value pairs */ - static async get (ids: string[], store: string): Promise> - static async get (ids: string | string[], store: string): Promise> { + static async get> (ids: string[], store: string): Promise> + static async get> (ids: string | string[], store: string): Promise> { if (!Array.isArray(ids)) ids = [ids] this.#storage ??= await this.#open(this.DB_NAME) const transaction = this.#storage.transaction(store, 'readonly') @@ -107,7 +107,7 @@ export class Database { return new Promise((resolve, reject) => { const requests = ids.map(id => db.get(id)) transaction.oncomplete = (event) => { - const results: NamedData = {} + const results: Record = {} for (const request of requests) { if (request?.result?.id != null) { results[request.result.id] = request.error ?? request.result @@ -125,9 +125,9 @@ export class Database { * Gets all records from a specific datastore. * * @param {string} store - Datastore from which to get records - * @returns {Promise} Object of key-value pairs + * @returns {Promise>>} Object of key-value pairs */ - static async getAll (store: string): Promise> { + static async getAll> (store: string): Promise> { this.#storage ??= await this.#open(this.DB_NAME) const transaction = this.#storage.transaction(store, 'readonly') const db = transaction.objectStore(store) @@ -139,7 +139,7 @@ export class Database { } else if (request.result == null) { reject('getAll request failed') } else { - const results: NamedData = {} + const results: Record = {} for (const result of request.result) { results[result.id] = request.error ?? result } @@ -155,11 +155,11 @@ export class Database { /** * Inserts records in a datastore, overwriting existing data. * - * @param {NamedData} data - Object of key-value pairs + * @param {Record>} data - Object of key-value pairs * @param {string} store - Datastore in which to put records * @returns {Promise<(IDBValidKey | DOMException)[]>} Index keys of the records inserted */ - static async put (data: NamedData, store: string): Promise<(IDBValidKey | DOMException)[]> { + static async put> (data: Record, store: string): Promise<(IDBValidKey | DOMException)[]> { this.#storage ??= await this.#open(this.DB_NAME) const transaction = this.#storage.transaction(store, 'readwrite') const db = transaction.objectStore(store) diff --git a/src/lib/rolodex.ts b/src/lib/rolodex.ts index a20f4de..acc04f2 100644 --- a/src/lib/rolodex.ts +++ b/src/lib/rolodex.ts @@ -1,7 +1,6 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { NamedData } from '#types' import { Account } from './account' import { Database } from './database' import { Tools } from './tools' @@ -55,11 +54,10 @@ export class Rolodex { if (existingName === name) { return true } - const data: NamedData = { - [address]: { - id: address, - name - } + const data: { [address: string]: { id: string, name: string } } | { [name: string]: { id: string, addresses: string[] } } = {} + data[address] = { + id: address, + name } if (existingName != null) { const addresses = (await this.getAddresses(existingName)) @@ -76,7 +74,7 @@ export class Rolodex { id: name, addresses } - const results = await Database.put(data, this.DB_NAME) + const results = await Database.put>(data, this.DB_NAME) if (results.length !== Object.keys(data).length) { throw new Error('Unexpected results from adding address', { cause: results }) } @@ -132,7 +130,7 @@ export class Rolodex { */ static async getAddresses (name: string): Promise { try { - const records = await Database.get>(name, this.DB_NAME) + const records = await Database.get>(name, this.DB_NAME) const record = records[name] return record?.addresses ? record.addresses.sort() @@ -150,7 +148,7 @@ export class Rolodex { */ static async getAllNames (): Promise { try { - const records = await Database.getAll(this.DB_NAME) + const records = await Database.getAll(this.DB_NAME) return Object.keys(records).filter(v => v.slice(0, 5) !== 'nano_') } catch (err) { console.error(err) @@ -166,7 +164,7 @@ export class Rolodex { */ static async getName (address: string): Promise { try { - const records = await Database.get>(address, this.DB_NAME) + const records = await Database.get>(address, this.DB_NAME) const record = records[address] return record?.name ?? null } catch (err) { diff --git a/src/lib/vault/index.ts b/src/lib/vault/index.ts index e9459bb..dcd7dec 100644 --- a/src/lib/vault/index.ts +++ b/src/lib/vault/index.ts @@ -2,16 +2,16 @@ //! SPDX-License-Identifier: GPL-3.0-or-later import { Worker as NodeWorker } from 'node:worker_threads' -import { Data, NamedData } from '#types' import { default as CONSTANTS } from '../constants' import { Bip39, Bip44, Blake2b, NanoNaCl, WalletAesGcm } from '../crypto' +import { Data } from '../database' import { Passkey } from './passkey' import { VaultTimer } from './vault-timer' import { VaultWorker } from './vault-worker' type Task = { id: number - data: NamedData + data: Record> reject: (value: any) => void resolve: (value: any) => void } @@ -51,10 +51,9 @@ export class Vault { }) } - get isLocked (): boolean { return this.#isLocked } - request (data: NamedData): Promise> { + request> (data: Record>): Promise> { return new Promise((resolve, reject): void => { if (this.#isTerminated) { return reject('Worker terminated') @@ -83,9 +82,9 @@ export class Vault { const { data, reject } = this.#job try { const buffers: ArrayBuffer[] = [] - for (let d of Object.keys(data)) { - if (data[d] instanceof ArrayBuffer) { - buffers.push(data[d]) + for (const d of Object.values(data)) { + if (d instanceof ArrayBuffer) { + buffers.push(d) } } BROWSER: this.#worker.postMessage(data, buffers) diff --git a/src/lib/vault/vault-worker.ts b/src/lib/vault/vault-worker.ts index 825e205..faa1ae9 100644 --- a/src/lib/vault/vault-worker.ts +++ b/src/lib/vault/vault-worker.ts @@ -1,7 +1,6 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { NamedData } from '#types' import { BIP44_COIN_NANO } from '../constants' import { Bip39, Bip44, Blake2b, NanoNaCl, WalletAesGcm } from '../crypto' import { WalletType } from '../wallet' @@ -35,7 +34,7 @@ export class VaultWorker { const action = this.#parseAction(data) const keySalt = this.#parseKeySalt(action, data) Passkey.create(action, keySalt, data) - .then((key: CryptoKey | undefined): Promise => { + .then((key: CryptoKey | undefined): Promise | void> => { const type = this.#parseType(action, data) const iv = this.#parseIv(action, data) const { seed, mnemonicPhrase, mnemonicSalt, index, encrypted, message, timeout } = this.#extractData(action, data) @@ -76,12 +75,12 @@ export class VaultWorker { } } }) - .then((result: NamedData | void) => { + .then((result: Record | void) => { const transfer = [] if (result) { - for (const k of Object.keys(result)) { - if (result[k] instanceof ArrayBuffer || result[k] instanceof CryptoKey) { - transfer.push(result[k]) + for (const r of Object.values(result)) { + if (r instanceof ArrayBuffer) { + transfer.push(r) } } } @@ -91,11 +90,11 @@ export class VaultWorker { }) .catch((err: any) => { console.error(err) - for (const key of Object.keys(event.data)) { - if (event.data[key] instanceof ArrayBuffer && !event.data[key].detached) { - new Uint8Array(event.data[key]).fill(0).buffer.transfer?.() + for (let data of Object.values(event.data)) { + if (data instanceof ArrayBuffer && !data.detached) { + new Uint8Array(data).fill(0).buffer.transfer?.() } - event.data[key] = undefined + data = undefined } BROWSER: postMessage({ error: 'Failed to process Vault request', cause: err }) NODE: this.#parentPort?.postMessage({ error: 'Failed to process Vault request', cause: err }) @@ -145,7 +144,7 @@ export class VaultWorker { * Generates a new mnemonic and seed and then returns the initialization vector * vector, salt, and encrypted data representing the wallet in a locked state. */ - create (type?: WalletType, key?: CryptoKey, keySalt?: ArrayBuffer, mnemonicSalt?: string): Promise> { + create (type?: WalletType, key?: CryptoKey, keySalt?: ArrayBuffer, mnemonicSalt?: string): Promise> { if (type !== 'BIP-44' && type !== 'BLAKE2b') { throw new TypeError('Unsupported software wallet algorithm', { cause: type }) } @@ -173,7 +172,7 @@ export class VaultWorker { * wallet seed at a specified index and then returns the public key. The wallet * must be unlocked prior to derivation. */ - derive (index?: number): Promise> { + derive (index?: number): Promise> { try { this.#timer.pause() if (this.#locked) { @@ -207,7 +206,7 @@ export class VaultWorker { * Encrypts an existing seed or mnemonic+salt and returns the initialization * vector, salt, and encrypted data representing the wallet in a locked state. */ - load (type?: WalletType, key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise> { + load (type?: WalletType, key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise> { if (type !== 'BIP-44' && type !== 'BLAKE2b') { throw new TypeError('Unsupported software wallet algorithm', { cause: type }) } @@ -239,7 +238,7 @@ export class VaultWorker { * Derives the account private key at a specified index, signs the input data, * and returns a signature. The wallet must be unlocked prior to verification. */ - sign (index?: number, data?: ArrayBuffer): Promise> { + sign (index?: number, data?: ArrayBuffer): Promise> { try { this.#timer.pause() if (this.#locked) { @@ -318,7 +317,7 @@ export class VaultWorker { /** * Re-encrypts the wallet with a new password. */ - update (key?: CryptoKey, salt?: ArrayBuffer): Promise> { + update (key?: CryptoKey, salt?: ArrayBuffer): Promise> { try { this.#timer.pause() if (this.#locked) { @@ -349,7 +348,7 @@ export class VaultWorker { * Checks the seed and, if it exists, the mnemonic against input. The wallet * must be unlocked prior to verification. */ - verify (seed?: ArrayBuffer, mnemonicPhrase?: string): NamedData { + verify (seed?: ArrayBuffer, mnemonicPhrase?: string): Record { try { if (this.#locked) { throw new Error('Wallet is locked') @@ -492,7 +491,7 @@ export class VaultWorker { * Encrypts an existing seed or mnemonic+salt and returns the initialization * vector, salt, and encrypted data representing the wallet in a locked state. */ - #load (type?: 'BIP-44' | 'BLAKE2b', key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise> { + #load (type?: 'BIP-44' | 'BLAKE2b', key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise> { try { if (!this.#locked) { throw new Error('Wallet is in use') diff --git a/src/lib/wallet/backup.ts b/src/lib/wallet/backup.ts index 860ecd3..bb8992f 100644 --- a/src/lib/wallet/backup.ts +++ b/src/lib/wallet/backup.ts @@ -1,23 +1,18 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { NamedData } from '#types' import { Database } from '../database' import { Wallet } from '../wallet' export async function _backup () { try { - const records = await Database.getAll(Wallet.DB_NAME) - const recordIds = Object.keys(records) - return recordIds.map(recordId => { - const { id, type, iv, salt, encrypted } = records[recordId] + const records = await Database.getAll>(Wallet.DB_NAME) + return Object.values(records).map((record: Record) => { + const { id, type, iv, salt, encrypted } = record if (typeof id !== 'string') { throw new TypeError('Retrieved invalid ID', { cause: id }) } - if (type === 'Ledger') { - return { id, type, iv: new ArrayBuffer(0), salt: new ArrayBuffer(0), encrypted: new ArrayBuffer(0) } as const - } - if (type !== 'BIP-44' && type !== 'BLAKE2b') { + if (type !== 'BIP-44' && type !== 'BLAKE2b' && type !== 'Ledger') { throw new TypeError('Retrieved invalid type', { cause: type }) } if (!(iv instanceof ArrayBuffer)) { diff --git a/src/lib/wallet/create.ts b/src/lib/wallet/create.ts index 20f44a9..cae4c49 100644 --- a/src/lib/wallet/create.ts +++ b/src/lib/wallet/create.ts @@ -1,38 +1,31 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { NamedData } from '#types' import { utf8 } from '../convert' import { Database } from '../database' import { Ledger } from '../ledger' import { Vault } from '../vault' import { Wallet } from '../wallet' -import { _load } from './load' -export async function _create (wallet: Wallet, vault: Vault, password?: string, mnemonicSalt?: string): Promise> -export async function _create (wallet: Wallet, vault: Vault, password: unknown, mnemonicSalt?: unknown): Promise> { +export async function _create (wallet: Wallet, vault: Vault, password?: string, mnemonicSalt?: string): Promise<{ mnemonic?: ArrayBuffer, seed?: ArrayBuffer }> +export async function _create (wallet: Wallet, vault: Vault, password: unknown, mnemonicSalt?: unknown): Promise<{ mnemonic?: ArrayBuffer, seed?: ArrayBuffer }> { try { - const result: NamedData = {} - const record: NamedData = { + const result: { mnemonic?: ArrayBuffer, seed?: ArrayBuffer } = {} + const record = { id: wallet.id, - type: wallet.type + type: wallet.type, + iv: new ArrayBuffer(0), + salt: new ArrayBuffer(0), + encrypted: new ArrayBuffer(0) } - if (wallet.type === 'Ledger') { - try { - if (Ledger.isUnsupported) { - throw new Error('Browser is unsupported') - } - } catch (err) { - throw new Error('Failed to initialize Ledger wallet', { cause: err }) - } - } else { + if (wallet.type !== 'Ledger') { if (typeof password !== 'string') { throw new TypeError('Password must be a string') } if (mnemonicSalt !== undefined && typeof mnemonicSalt !== 'string') { throw new TypeError('Mnemonic salt must be a string') } - const response = await vault.request({ + const pending = vault.request({ action: 'create', type: wallet.type, password: utf8.toBuffer(password), @@ -40,11 +33,16 @@ export async function _create (wallet: Wallet, vault: Vault, password: unknown, }) password = undefined mnemonicSalt = undefined + const response = await pending record.iv = response.iv record.salt = response.salt record.encrypted = response.encrypted result.mnemonic = response.mnemonic result.seed = response.seed + } else { + if (Ledger.isUnsupported) { + throw new Error('Failed to initialize Ledger wallet', { cause: 'Browser is unsupported' }) + } } await Database.add({ [wallet.id]: record }, Wallet.DB_NAME) return result diff --git a/src/lib/wallet/get.ts b/src/lib/wallet/get.ts index 2d8d352..412befd 100644 --- a/src/lib/wallet/get.ts +++ b/src/lib/wallet/get.ts @@ -1,13 +1,12 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { NamedData } from '#types' import { Database } from '../database' import { Wallet } from '../wallet' export async function _get (recordId: string) { try { - const record = await Database.get(recordId, Wallet.DB_NAME) + const record = await Database.get>(recordId, Wallet.DB_NAME) const { id, type, iv, salt, encrypted } = record[recordId] if (typeof id !== 'string') { throw new TypeError('Retrieved invalid ID', { cause: id }) @@ -15,16 +14,14 @@ export async function _get (recordId: string) { if (type !== 'BIP-44' && type !== 'BLAKE2b' && type !== 'Ledger') { throw new TypeError('Retrieved invalid type', { cause: type }) } - if (type !== 'Ledger') { - if (!(iv instanceof ArrayBuffer)) { - throw new TypeError('Retrieved invalid iv', { cause: iv }) - } - if (!(salt instanceof ArrayBuffer)) { - throw new TypeError('Retrieved invalid salt', { cause: salt }) - } - if (!(encrypted instanceof ArrayBuffer)) { - throw new TypeError('Retrieved invalid encrypted data', { cause: encrypted }) - } + if (!(iv instanceof ArrayBuffer)) { + throw new TypeError('Retrieved invalid iv', { cause: iv }) + } + if (!(salt instanceof ArrayBuffer)) { + throw new TypeError('Retrieved invalid salt', { cause: salt }) + } + if (!(encrypted instanceof ArrayBuffer)) { + throw new TypeError('Retrieved invalid encrypted data', { cause: encrypted }) } return { id, type, iv, salt, encrypted } as const } catch (err) { diff --git a/src/lib/wallet/index.ts b/src/lib/wallet/index.ts index c042bda..0c287de 100644 --- a/src/lib/wallet/index.ts +++ b/src/lib/wallet/index.ts @@ -1,7 +1,6 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { NamedData } from '#types' import { Account } from '../account' import { Block } from '../block' import { ADDRESS_GAP } from '../constants' @@ -47,9 +46,9 @@ export class Wallet { * Retrieves all wallets with encrypted secrets and unencrypted metadata from * the database. * - * @returns id, type, iv, salt, encrypted + * @returns Array of objects with properties: id, type, iv, salt, encrypted */ - static async backup (): Promise { + static async backup () { return _backup() } @@ -74,7 +73,9 @@ export class Wallet { this.#isInternal = true const self = new this(type) this.#isInternal = false - { ({ mnemonic: self.#mnemonic, seed: self.#seed } = await _create(self, self.#vault, password, mnemonicSalt)) } + const pending = _create(self, self.#vault, password, mnemonicSalt) + password = undefined + { ({ mnemonic: self.#mnemonic, seed: self.#seed } = await pending) } return self } @@ -103,7 +104,9 @@ export class Wallet { this.#isInternal = true const self = new this(type) this.#isInternal = false - await _load(self, self.#vault, password, secret, mnemonicSalt) + const pending = _load(self, self.#vault, password, secret, mnemonicSalt) + password = undefined! + await pending return self } @@ -371,7 +374,9 @@ export class Wallet { */ async unlock (password: string): Promise async unlock (password?: string): Promise { - await _unlock(this, this.#vault, password) + const pending = _unlock(this, this.#vault, password) + password = undefined + await pending } /** @@ -394,7 +399,9 @@ export class Wallet { * @param {string} password Used to re-encrypt the wallet */ async update (password: string): Promise { - await _update(this, this.#vault, password) + const pending = _update(this, this.#vault, password) + password = undefined! + await pending } /** diff --git a/src/lib/wallet/load.ts b/src/lib/wallet/load.ts index dee3b57..fc73b83 100644 --- a/src/lib/wallet/load.ts +++ b/src/lib/wallet/load.ts @@ -1,7 +1,6 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { NamedData } from '#types' import { hex, utf8 } from '../convert' import { Bip39 } from '../crypto' import { Database } from '../database' @@ -12,9 +11,12 @@ import { Wallet } from '../wallet' export async function _load (wallet: Wallet, vault: Vault, password: string, secret: string, mnemonicSalt?: string): Promise export async function _load (wallet: Wallet, vault: Vault, password: unknown, secret: unknown, mnemonicSalt?: unknown): Promise { try { - const record: NamedData = { + const record = { id: wallet.id, - type: wallet.type + type: wallet.type, + iv: new ArrayBuffer(0), + salt: new ArrayBuffer(0), + encrypted: new ArrayBuffer(0) } if (wallet.type === 'Ledger') { if (Ledger.isUnsupported) { @@ -33,7 +35,7 @@ export async function _load (wallet: Wallet, vault: Vault, password: unknown, se if (mnemonicSalt !== undefined && typeof mnemonicSalt !== 'string') { throw new TypeError('Mnemonic salt must be a string') } - const data: NamedData = { + const data: Record = { action: 'load', type: wallet.type, password: utf8.toBuffer(password) diff --git a/src/lib/wallet/unlock.ts b/src/lib/wallet/unlock.ts index 0c7cadd..b6be264 100644 --- a/src/lib/wallet/unlock.ts +++ b/src/lib/wallet/unlock.ts @@ -1,7 +1,6 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { NamedData } from '#types' import { utf8 } from '../convert' import { Ledger } from '../ledger' import { Vault } from '../vault' @@ -11,30 +10,30 @@ import { _get } from './get' export async function _unlock (wallet: Wallet, vault: Vault, password?: string): Promise export async function _unlock (wallet: Wallet, vault: Vault, password: unknown): Promise { try { - const data: NamedData = { - action: 'unlock', - type: wallet.type - } - if (wallet.type === 'Ledger') { + if (wallet.type !== 'Ledger') { + if (typeof password !== 'string') { + throw new TypeError('Password must be a string') + } + const data = { + action: 'unlock', + type: wallet.type, + password: utf8.toBuffer(password), + iv: new ArrayBuffer(0), + keySalt: new ArrayBuffer(0), + encrypted: new ArrayBuffer(0) + } + password = undefined + const record = await _get(wallet.id) + data.iv = record.iv + data.keySalt = record.salt + data.encrypted = record.encrypted + await vault.request(data) + } else { const status = await Ledger.connect() if (await status !== 'CONNECTED') { throw new Error('Failed to unlock wallet', { cause: status }) } - data.password = new ArrayBuffer(0) - data.iv = new ArrayBuffer(0) - data.keySalt = new ArrayBuffer(0) - data.encrypted = new ArrayBuffer(0) - } else { - if (typeof password !== 'string') { - throw new TypeError('Password must be a string') - } - const { iv, salt, encrypted } = await _get(wallet.id) - data.password = utf8.toBuffer(password) - data.iv = iv - data.keySalt = salt - data.encrypted = encrypted } - await vault.request(data) if (wallet.isLocked) { throw new Error('Unlock request failed') } diff --git a/src/lib/wallet/update.ts b/src/lib/wallet/update.ts index 1199c16..9859baf 100644 --- a/src/lib/wallet/update.ts +++ b/src/lib/wallet/update.ts @@ -1,7 +1,6 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { NamedData } from '#types' import { utf8 } from '../convert' import { Database } from '../database' import { Vault } from '../vault' @@ -10,26 +9,25 @@ import { Wallet } from '../wallet' export async function _update (wallet: Wallet, vault: Vault, password?: string): Promise export async function _update (wallet: Wallet, vault: Vault, password: unknown): Promise { try { - const record: NamedData = { - id: wallet.id, - type: wallet.type - } - if (wallet.type === 'Ledger') { - return - } else { + if (wallet.type !== 'Ledger') { if (typeof password !== 'string') { throw new TypeError('Password must be a string') } - const response = await vault.request({ + const pending = vault.request({ action: 'update', password: utf8.toBuffer(password) }) password = undefined - record.iv = response.iv - record.salt = response.salt - record.encrypted = response.encrypted + const response = await pending + const record = { + id: wallet.id, + type: wallet.type, + iv: response.iv, + salt: response.salt, + encrypted: response.encrypted + } + await Database.put({ [wallet.id]: record }, Wallet.DB_NAME) } - await Database.put({ [wallet.id]: record }, Wallet.DB_NAME) } catch (err) { throw new Error('Failed to unlock wallet', { cause: err }) } diff --git a/src/types.d.ts b/src/types.d.ts deleted file mode 100644 index 0daa045..0000000 --- a/src/types.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -//! SPDX-FileCopyrightText: 2025 Chris Duncan -//! SPDX-License-Identifier: GPL-3.0-or-later - -export type Data = boolean | number | number[] | string | string[] | ArrayBuffer | CryptoKey | { [key: string]: Data } - -export type NamedData = { - [key: string]: T -} -- 2.47.3