//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
//! SPDX-License-Identifier: GPL-3.0-or-later
-import { NamedData } from '#types'
+import { NamedData, WalletType } from '#types'
import { BIP44_COIN_NANO } from '../constants'
import { Bip39, Bip44, Blake2b, NanoNaCl, WalletAesGcm } from '../crypto'
import { Passkey } from './passkey'
* 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?: 'BIP-44' | 'BLAKE2b', key?: CryptoKey, keySalt?: ArrayBuffer, mnemonicSalt?: string): Promise<NamedData<ArrayBuffer>> {
+ create (type?: WalletType, key?: CryptoKey, keySalt?: ArrayBuffer, mnemonicSalt?: string): Promise<NamedData<ArrayBuffer>> {
+ if (type !== 'BIP-44' && type !== 'BLAKE2b') {
+ throw new TypeError('Unsupported software wallet algorithm', { cause: type })
+ }
try {
const entropy = crypto.getRandomValues(new Uint8Array(32))
return Bip39.fromEntropy(entropy)
* 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<NamedData<ArrayBuffer>> {
+ load (type?: WalletType, key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise<NamedData<ArrayBuffer>> {
+ if (type !== 'BIP-44' && type !== 'BLAKE2b') {
+ throw new TypeError('Unsupported software wallet algorithm', { cause: type })
+ }
return this.#load(type, key, keySalt, secret, mnemonicSalt)
.then(record => {
if (this.#seed == null) {
if (type == null) {
throw new TypeError('Wallet type is required')
}
+ if (type === 'Ledger') {
+ this.#locked = false
+ BROWSER: postMessage('unlocked')
+ NODE: this.#parentPort?.postMessage('unlocked')
+ return Promise.resolve()
+ }
if (key == null) {
throw new TypeError('Wallet password is required')
}
// Algorithm used for wallet functions
#parseType (action: string, data: { [key: string]: unknown }) {
if (['create', 'load', 'unlock'].includes(action)) {
- if (data.type !== 'BIP-44' && data.type !== 'BLAKE2b') {
+ if (data.type !== 'BIP-44' && data.type !== 'BLAKE2b' && data.type !== 'Ledger') {
throw new TypeError(`Type is required to ${action} wallet`)
}
} else if (data.type !== undefined) {
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
//! SPDX-License-Identifier: GPL-3.0-or-later
+import { NamedData } from '#types'
import { utf8 } from '../convert'
import { Vault } from '../vault'
import { Wallet } from '../wallet'
export async function _unlock (wallet: Wallet, vault: Vault, password?: string): Promise<void>
export async function _unlock (wallet: Wallet, vault: Vault, password: unknown): Promise<void> {
try {
+ const data: NamedData = {
+ action: 'unlock',
+ type: wallet.type
+ }
if (wallet.type === 'Ledger') {
const { Ledger } = await import('./ledger')
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)
- await vault.request({
- action: 'unlock',
- type: wallet.type,
- password: utf8.toBuffer(password),
- iv,
- keySalt: salt,
- encrypted
- })
- if (wallet.isLocked) {
- throw new Error('Unlock request to Vault failed')
- }
+ 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')
}
} catch (err) {
throw new Error('Failed to unlock wallet', { cause: err })
await test('request permissions', async () => {
await assert.rejects(wallet.unlock(), 'expect DISCONNECTED')
+ assert.equal(wallet.isLocked, true)
await assert.rejects(async () => {
await click(
async () => wallet.unlock()
)
}, 'expect BUSY')
+ assert.equal(wallet.isLocked, true)
await assert.rejects(async () => {
await click(
async () => wallet.unlock()
)
}, 'expect LOCKED')
+ assert.equal(wallet.isLocked, true)
await assert.resolves(async () => {
await click(
async () => wallet.unlock()
)
}, 'expect CONNECTED')
+ assert.equal(wallet.isLocked, false)
})
await test('get first account', async () => {