From 23a5f092d833f2ea88c25b8ccdf7b6ad9b0fbe6b Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sun, 6 Jul 2025 00:23:30 -0700 Subject: [PATCH] Create wallet IDs from full 256-bit entropy. Change name of public method for putting items in Safe. Never overwrite Safe entries. --- src/lib/wallets/bip44-wallet.ts | 6 +++--- src/lib/wallets/blake2b-wallet.ts | 4 ++-- src/lib/wallets/wallet.ts | 15 ++++++++------- src/lib/workers/safe.ts | 25 +++++++------------------ 4 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/lib/wallets/bip44-wallet.ts b/src/lib/wallets/bip44-wallet.ts index 0b4865a..2632535 100644 --- a/src/lib/wallets/bip44-wallet.ts +++ b/src/lib/wallets/bip44-wallet.ts @@ -93,7 +93,7 @@ export class Bip44Wallet extends Wallet { static async fromEntropy (passkey: string | Uint8Array, entropy: string, salt: string = ''): Promise { let wallet: Bip44Wallet try { - const id = await Entropy.create(16) + const id = await Entropy.create() const e = await Entropy.import(entropy) const m = await Bip39Mnemonic.fromEntropy(e.hex) const s = await m.toBip39Seed(salt) @@ -132,7 +132,7 @@ export class Bip44Wallet extends Wallet { static async fromMnemonic (passkey: string | Uint8Array, mnemonic: string, salt: string = ''): Promise { let wallet: Bip44Wallet try { - const id = await Entropy.create(16) + const id = await Entropy.create() const m = await Bip39Mnemonic.fromPhrase(mnemonic) const s = await m.toBip39Seed(salt) Bip44Wallet.#isInternal = true @@ -176,7 +176,7 @@ export class Bip44Wallet extends Wallet { if (!/^[0-9a-fA-F]+$/i.test(seed)) { throw new Error('Seed contains invalid hexadecimal characters.') } - const id = await Entropy.create(16) + const id = await Entropy.create() Bip44Wallet.#isInternal = true const wallet = new this(id, seed) try { diff --git a/src/lib/wallets/blake2b-wallet.ts b/src/lib/wallets/blake2b-wallet.ts index 880bd32..c2a405d 100644 --- a/src/lib/wallets/blake2b-wallet.ts +++ b/src/lib/wallets/blake2b-wallet.ts @@ -85,7 +85,7 @@ export class Blake2bWallet extends Wallet { if (!/^[0-9a-fA-F]+$/i.test(seed)) { throw new Error('Seed contains invalid hexadecimal characters.') } - const id = await Entropy.create(16) + const id = await Entropy.create() const s = seed const m = await Bip39Mnemonic.fromEntropy(seed) Blake2bWallet.#isInternal = true @@ -118,7 +118,7 @@ export class Blake2bWallet extends Wallet { static async fromMnemonic (passkey: string | Uint8Array, mnemonic: string): Promise { let wallet: Blake2bWallet try { - const id = await Entropy.create(16) + const id = await Entropy.create() const m = await Bip39Mnemonic.fromPhrase(mnemonic) const s = await m.toBlake2bSeed() Blake2bWallet.#isInternal = true diff --git a/src/lib/wallets/wallet.ts b/src/lib/wallets/wallet.ts index 4a68517..b2efda7 100644 --- a/src/lib/wallets/wallet.ts +++ b/src/lib/wallets/wallet.ts @@ -152,7 +152,8 @@ export abstract class Wallet { } /** - * Locks the wallet with a password that will be needed to unlock it later. + * Locks the wallet and all currently derived accounts with a password that + * will be needed to unlock it later. * * @param {(string|Uint8Array)} password Used to lock the wallet * @returns True if successfully locked @@ -177,12 +178,12 @@ export abstract class Wallet { data.seed = this.#s } const response = (await Wallet.#poolSafe.assign({ - method: 'put', + method: 'set', name: this.id, password, data }))[0] - const success = response.result + const success = response?.result if (!success) { throw null } @@ -196,9 +197,9 @@ export abstract class Wallet { } finally { password.fill(0) } - this.#locked = true this.#m = null this.#s = null + this.#locked = true return true } @@ -248,8 +249,8 @@ export abstract class Wallet { name: this.id, password }))[0] - const { id, mnemonic, seed } = response.result - if (id !== this.id) { + const { id, mnemonic, seed } = response?.result + if (id == null || id !== this.id) { throw null } if (mnemonic != null) { @@ -263,12 +264,12 @@ export abstract class Wallet { promises.push(account.unlock(password)) } await Promise.all(promises) - this.#locked = false } catch (err) { throw new Error('Failed to unlock wallet') } finally { password.fill(0) } + this.#locked = false return true } diff --git a/src/lib/workers/safe.ts b/src/lib/workers/safe.ts index d3c21ff..5af2b60 100644 --- a/src/lib/workers/safe.ts +++ b/src/lib/workers/safe.ts @@ -46,13 +46,9 @@ export class Safe extends WorkerInterface { let result try { const passwordBytes = obj.toBytes(password ?? []) - switch (d.method) { - case 'put': { - result = await this.put(name, passwordBytes, data) - break - } - case 'overwrite': { - result = await this.overwrite(name, passwordBytes, data) + switch (method) { + case 'set': { + result = await this.set(name, passwordBytes, data) break } case 'get': { @@ -89,18 +85,11 @@ export class Safe extends WorkerInterface { /** * Encrypts data with a password byte array and stores it in the Safe. */ - static async put (name: string, password: Uint8Array, data: any): Promise { + static async set (name: string, password: Uint8Array, data: any): Promise { if (await this.#exists(name)) { password.fill(0) throw new Error(this.ERR_MSG) } - return this.overwrite(name, password, data) - } - - /** - * Encrypts data with a password byte array and stores it in the Safe. - */ - static async overwrite (name: string, password: Uint8Array, data: any): Promise { let passkey: CryptoKey try { passkey = await globalThis.crypto.subtle.importKey('raw', password, 'PBKDF2', false, ['deriveBits', 'deriveKey']) @@ -132,7 +121,7 @@ export class Safe extends WorkerInterface { encrypted: bytes.toHex(new Uint8Array(encrypted)), iv: iv.hex } - return await this.#put(record, name) + return await this.#add(record, name) } catch (err) { throw new Error(this.ERR_MSG) } @@ -244,8 +233,8 @@ export class Safe extends WorkerInterface { }) } - static async #put (record: SafeRecord, name: string): Promise { - const result = await this.#transact('readwrite', db => db.put(record, name)) + static async #add (record: SafeRecord, name: string): Promise { + const result = await this.#transact('readwrite', db => db.add(record, name)) return await this.#exists(result) } -- 2.47.3