From: Chris Duncan Date: Fri, 8 Aug 2025 18:29:25 +0000 (-0700) Subject: Extract wallet import to private method called by both create and import API methods. X-Git-Tag: v0.10.5~43^2~18 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=72fa4961ee0bc356cbafeeb96f7a3df1978f8cd9;p=libnemo.git Extract wallet import to private method called by both create and import API methods. --- diff --git a/src/lib/safe.ts b/src/lib/safe.ts index 55c8b29..aea0ea9 100644 --- a/src/lib/safe.ts +++ b/src/lib/safe.ts @@ -112,13 +112,15 @@ export class Safe { try { const entropy = crypto.getRandomValues(new Uint8Array(32)) const { phrase: mnemonicPhrase } = await Bip39.fromEntropy(entropy) - const record = await this.import(type, key, keySalt, mnemonicPhrase, mnemonicSalt) + const record = await this.#import(type, key, keySalt, mnemonicPhrase, mnemonicSalt) if (this.#seed == null || this.#mnemonic == null) { throw new Error('Failed to generate seed and mnemonic') } return { ...record, seed: this.#seed.slice(), mnemonic: utf8.toBuffer(this.#mnemonic) } } catch (err) { throw new Error('Failed to create wallet', { cause: err }) + } finally { + this.lock() } } @@ -157,52 +159,15 @@ export class Safe { */ static async import (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') - } - if (key == null || keySalt == null) { - throw new Error('Wallet password is required') - } - if (type == null) { - throw new TypeError('Wallet type is required') - } - if (type !== 'BIP-44' && type !== 'BLAKE2b') { - throw new TypeError('Invalid wallet type') - } - if (secret == null) { - throw new TypeError('Seed or mnemonic is required') - } - if (typeof secret !== 'string' && mnemonicSalt !== undefined) { - throw new TypeError('Mnemonic must be a string') - } - if (type === 'BIP-44') { - if (secret instanceof ArrayBuffer && (secret.byteLength < 16 || secret.byteLength > 64)) { - throw new RangeError('Seed for BIP-44 wallet must be 16-64 bytes') - } - } - if (type === 'BLAKE2b') { - if (secret instanceof ArrayBuffer && secret.byteLength !== 32) { - throw new RangeError('Seed for BLAKE2b wallet must be 32 bytes') - } - } - this.#type = type - if (secret instanceof ArrayBuffer) { - this.#seed = secret - if (type === 'BLAKE2b') { - this.#mnemonic = (await Bip39.fromEntropy(new Uint8Array(secret))).phrase - } - } else { - const mnemonic = await Bip39.fromPhrase(secret) - this.#mnemonic = mnemonic.phrase - this.#seed = type === 'BIP-44' - ? (await mnemonic.toBip39Seed(mnemonicSalt ?? '')).buffer - : (await mnemonic.toBlake2bSeed()).buffer + const record = await this.#import(type, key, keySalt, secret, mnemonicSalt) + if (this.#seed == null) { + throw new Error('Wallet seed not found') } - const { iv, encrypted } = await this.#encryptWallet(key) - return { iv, salt: keySalt, encrypted } + return record } catch (err) { - this.lock() throw new Error('Failed to import wallet', { cause: err }) + } finally { + this.lock() } } @@ -522,6 +487,60 @@ export class Safe { return { action, type, key, iv, keySalt, seed, mnemonicPhrase, mnemonicSalt, encrypted, index, data } } + + /** + * Encrypts an existing seed or mnemonic+salt and returns the initialization + * vector, salt, and encrypted data representing the wallet in a locked state. + */ + static async #import (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') + } + if (key == null || keySalt == null) { + throw new Error('Wallet password is required') + } + if (type == null) { + throw new TypeError('Wallet type is required') + } + if (type !== 'BIP-44' && type !== 'BLAKE2b') { + throw new TypeError('Invalid wallet type') + } + if (secret == null) { + throw new TypeError('Seed or mnemonic is required') + } + if (typeof secret !== 'string' && mnemonicSalt !== undefined) { + throw new TypeError('Mnemonic must be a string') + } + if (type === 'BIP-44') { + if (secret instanceof ArrayBuffer && (secret.byteLength < 16 || secret.byteLength > 64)) { + throw new RangeError('Seed for BIP-44 wallet must be 16-64 bytes') + } + } + if (type === 'BLAKE2b') { + if (secret instanceof ArrayBuffer && secret.byteLength !== 32) { + throw new RangeError('Seed for BLAKE2b wallet must be 32 bytes') + } + } + this.#type = type + if (secret instanceof ArrayBuffer) { + this.#seed = secret + if (type === 'BLAKE2b') { + this.#mnemonic = (await Bip39.fromEntropy(new Uint8Array(secret))).phrase + } + } else { + const mnemonic = await Bip39.fromPhrase(secret) + this.#mnemonic = mnemonic.phrase + this.#seed = type === 'BIP-44' + ? (await mnemonic.toBip39Seed(mnemonicSalt ?? '')).buffer + : (await mnemonic.toBlake2bSeed()).buffer + } + const { iv, encrypted } = await this.#encryptWallet(key) + return { iv, salt: keySalt, encrypted } + } catch (err) { + throw new Error('Failed to import wallet', { cause: err }) + } + } } let importWorkerThreads = ''