From 0d6283144dbf66956480d6700a75151a6afc33d4 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sat, 30 Aug 2025 00:45:09 -0700 Subject: [PATCH] Remove privatization of vault worker properties. --- src/lib/vault/vault-worker.ts | 150 +++++++++++++++++----------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/src/lib/vault/vault-worker.ts b/src/lib/vault/vault-worker.ts index 57840a6..f7ba724 100644 --- a/src/lib/vault/vault-worker.ts +++ b/src/lib/vault/vault-worker.ts @@ -12,20 +12,20 @@ import { VaultTimer } from './vault-timer' * Cross-platform worker for managing wallet secrets. */ export class VaultWorker { - static #locked: boolean = true - static #timeout: VaultTimer - static #type?: 'BIP-44' | 'BLAKE2b' - static #seed?: ArrayBuffer - static #mnemonic?: ArrayBuffer - static #parentPort?: any + static locked: boolean = true + static timeout: VaultTimer + static type?: 'BIP-44' | 'BLAKE2b' + static seed?: ArrayBuffer + static mnemonic?: ArrayBuffer + static parentPort?: any static { - NODE: this.#parentPort = parentPort + NODE: this.parentPort = parentPort } static { - NODE: this.#parentPort = parentPort + NODE: this.parentPort = parentPort const listener = (message: MessageEvent): Promise => { - return this.#extractData(message.data).then(extracted => { + return this._extractData(message.data).then(extracted => { const { action, type, @@ -107,7 +107,7 @@ export class VaultWorker { }) } BROWSER: addEventListener('message', listener) - NODE: this.#parentPort?.on('message', listener) + NODE: this.parentPort?.on('message', listener) } /** @@ -119,12 +119,12 @@ export class VaultWorker { const entropy = crypto.getRandomValues(new Uint8Array(32)) return Bip39.fromEntropy(entropy) .then(bip39 => { - return this.#load(type, key, keySalt, bip39.phrase, mnemonicSalt) + return this._load(type, key, keySalt, bip39.phrase, mnemonicSalt) .then(record => { - if (this.#seed == null || this.#mnemonic == null) { + if (this.seed == null || this.mnemonic == null) { throw new Error('Failed to generate seed and mnemonic') } - return { ...record, seed: this.#seed.slice(), mnemonic: this.#mnemonic.slice() } + return { ...record, seed: this.seed.slice(), mnemonic: this.mnemonic.slice() } }) }) } catch (err) { @@ -142,30 +142,30 @@ export class VaultWorker { */ static derive (index?: number): Promise> { try { - this.#timeout.pause() - if (this.#locked) { + this.timeout.pause() + if (this.locked) { throw new Error('Wallet is locked') } - if (this.#seed == null) { + if (this.seed == null) { throw new Error('Wallet seed not found') } - if (this.#type !== 'BIP-44' && this.#type !== 'BLAKE2b') { + if (this.type !== 'BIP-44' && this.type !== 'BLAKE2b') { throw new Error('Invalid wallet type') } if (typeof index !== 'number') { throw new Error('Invalid wallet account index') } - const derive = this.#type === 'BIP-44' - ? Bip44.ckd(this.#seed, BIP44_COIN_NANO, index) - : Promise.resolve(this.#deriveBlake2bPrivateKey(this.#seed, index)) + const derive = this.type === 'BIP-44' + ? Bip44.ckd(this.seed, BIP44_COIN_NANO, index) + : Promise.resolve(this._deriveBlake2bPrivateKey(this.seed, index)) return derive.then(prv => { const pub = NanoNaCl.convert(new Uint8Array(prv)) - this.#timeout = new VaultTimer(() => this.lock(), 120000) + this.timeout = new VaultTimer(() => this.lock(), 120000) return { index, publicKey: pub.buffer } }) } catch (err) { console.error(err) - this.#timeout.resume() + this.timeout.resume() throw new Error('Failed to derive account', { cause: err }) } } @@ -175,9 +175,9 @@ export class VaultWorker { * vector, salt, and encrypted data representing the wallet in a locked state. */ static load (type?: 'BIP-44' | 'BLAKE2b', key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise> { - return this.#load(type, key, keySalt, secret, mnemonicSalt) + return this._load(type, key, keySalt, secret, mnemonicSalt) .then(record => { - if (this.#seed == null) { + if (this.seed == null) { throw new Error('Wallet seed not found') } return record @@ -190,11 +190,11 @@ export class VaultWorker { } static lock (): NamedData { - this.#mnemonic = undefined - this.#seed = undefined - this.#locked = true - this.#timeout?.pause() - return { isLocked: this.#locked } + this.mnemonic = undefined + this.seed = undefined + this.locked = true + this.timeout?.pause() + return { isLocked: this.locked } } /** @@ -203,11 +203,11 @@ export class VaultWorker { */ static sign (index?: number, data?: ArrayBuffer): Promise> { try { - this.#timeout.pause() - if (this.#locked) { + this.timeout.pause() + if (this.locked) { throw new Error('Wallet is locked') } - if (this.#seed == null) { + if (this.seed == null) { throw new Error('Wallet seed not found') } if (index == null) { @@ -216,17 +216,17 @@ export class VaultWorker { if (data == null) { throw new Error('Data to sign not found') } - const derive = this.#type === 'BIP-44' - ? Bip44.ckd(this.#seed, BIP44_COIN_NANO, index) - : Promise.resolve(this.#deriveBlake2bPrivateKey(this.#seed, index)) + const derive = this.type === 'BIP-44' + ? Bip44.ckd(this.seed, BIP44_COIN_NANO, index) + : Promise.resolve(this._deriveBlake2bPrivateKey(this.seed, index)) return derive.then(prv => { const sig = NanoNaCl.detached(new Uint8Array(data), new Uint8Array(prv)) - this.#timeout = new VaultTimer(() => this.lock(), 120000) + this.timeout = new VaultTimer(() => this.lock(), 120000) return { signature: sig.buffer } }) } catch (err) { console.error(err) - this.#timeout.resume() + this.timeout.resume() throw new Error('Failed to sign message', { cause: err }) } } @@ -247,22 +247,22 @@ export class VaultWorker { if (encrypted == null) { throw new TypeError('Wallet encrypted data is required') } - this.#timeout?.pause() - return this.#decryptWallet(type, key, iv, encrypted) + this.timeout?.pause() + return this._decryptWallet(type, key, iv, encrypted) .then(() => { - if (!(this.#seed instanceof ArrayBuffer)) { + if (!(this.seed instanceof ArrayBuffer)) { throw new TypeError('Invalid seed') } - if (this.#mnemonic != null && !(this.#mnemonic instanceof ArrayBuffer)) { + if (this.mnemonic != null && !(this.mnemonic instanceof ArrayBuffer)) { throw new TypeError('Invalid mnemonic') } - this.#locked = false - this.#timeout = new VaultTimer(() => this.lock(), 120000) - return { isUnlocked: !this.#locked } + this.locked = false + this.timeout = new VaultTimer(() => this.lock(), 120000) + return { isUnlocked: !this.locked } }) .catch(err => { console.error(err) - this.#timeout?.resume() + this.timeout?.resume() throw new Error('Failed to unlock wallet', { cause: err }) }) } @@ -272,24 +272,24 @@ export class VaultWorker { */ static update (key?: CryptoKey, keySalt?: ArrayBuffer): Promise> { try { - this.#timeout.pause() - if (this.#locked) { + this.timeout.pause() + if (this.locked) { throw new Error('Wallet is locked') } - if (this.#seed == null) { + if (this.seed == null) { throw new Error('Wallet seed not found') } if (key == null || keySalt == null) { throw new TypeError('Wallet password is required') } - return this.#encryptWallet(key) + return this._encryptWallet(key) .then(({ iv, encrypted }) => { - this.#timeout = new VaultTimer(() => this.lock(), 120000) + this.timeout = new VaultTimer(() => this.lock(), 120000) return { iv, salt: keySalt, encrypted } }) } catch (err) { console.error(err) - this.#timeout.resume() + this.timeout.resume() throw new Error('Failed to update wallet password', { cause: err }) } } @@ -300,10 +300,10 @@ export class VaultWorker { */ static verify (seed?: ArrayBuffer, mnemonicPhrase?: string): NamedData { try { - if (this.#locked) { + if (this.locked) { throw new Error('Wallet is locked') } - if (this.#seed == null) { + if (this.seed == null) { throw new Error('Wallet seed not found') } if (seed == null && mnemonicPhrase == null) { @@ -316,7 +316,7 @@ export class VaultWorker { if (seed != null) { let diff = 0 const userSeed = new Uint8Array(seed) - const thisSeed = new Uint8Array(this.#seed) + const thisSeed = new Uint8Array(this.seed) for (let i = 0; i < userSeed.byteLength; i++) { diff |= userSeed[i] ^ thisSeed[i] } @@ -325,7 +325,7 @@ export class VaultWorker { if (mnemonicPhrase != null) { let diff = 0 const userMnemonic = utf8.toBytes(mnemonicPhrase) - const thisMnemonic = new Uint8Array(this.#mnemonic ?? []) + const thisMnemonic = new Uint8Array(this.mnemonic ?? []) for (let i = 0; i < userMnemonic.byteLength; i++) { diff |= userMnemonic[i] ^ thisMnemonic[i] } @@ -338,7 +338,7 @@ export class VaultWorker { } } - static #createAesKey (purpose: 'encrypt' | 'decrypt', keySalt: ArrayBuffer, password?: ArrayBuffer): Promise { + static _createAesKey (purpose: 'encrypt' | 'decrypt', keySalt: ArrayBuffer, password?: ArrayBuffer): Promise { return new Promise((resolve, reject): void => { if (password == null) { resolve(undefined) @@ -369,13 +369,13 @@ export class VaultWorker { }) } - static #decryptWallet (type: string, key: CryptoKey, iv: ArrayBuffer, encrypted: ArrayBuffer): Promise { + static _decryptWallet (type: string, key: CryptoKey, iv: ArrayBuffer, encrypted: ArrayBuffer): Promise { const seedLength = type === 'BIP-44' ? 64 : 32 const additionalData = utf8.toBytes(type) return crypto.subtle.decrypt({ name: 'AES-GCM', iv, additionalData }, key, encrypted) .then(decrypted => { - this.#seed = decrypted.slice(0, seedLength) - this.#mnemonic = decrypted.slice(seedLength) + this.seed = decrypted.slice(0, seedLength) + this.mnemonic = decrypted.slice(seedLength) new Uint8Array(decrypted).fill(0) }) } @@ -393,7 +393,7 @@ export class VaultWorker { * @param {number} index - 4-byte index of account to derive * @returns {ArrayBuffer} Private key for the account */ - static #deriveBlake2bPrivateKey (seed: ArrayBuffer, index: number): ArrayBuffer { + static _deriveBlake2bPrivateKey (seed: ArrayBuffer, index: number): ArrayBuffer { const b = new ArrayBuffer(4) new DataView(b).setUint32(0, index, false) const s = new Uint8Array(seed) @@ -401,18 +401,18 @@ export class VaultWorker { return new Blake2b(32).update(s).update(i).digest().buffer } - static #encryptWallet (key: CryptoKey): Promise> { - if (this.#type == null) { + static _encryptWallet (key: CryptoKey): Promise> { + if (this.type == null) { throw new Error('Invalid wallet type') } - if (this.#seed == null) { + if (this.seed == null) { throw new Error('Wallet seed not found') } - const seed = new Uint8Array(this.#seed) - const mnemonic = new Uint8Array(this.#mnemonic ?? []) + const seed = new Uint8Array(this.seed) + const mnemonic = new Uint8Array(this.mnemonic ?? []) // restrict iv to 96 bits per GCM best practice const iv = crypto.getRandomValues(new Uint8Array(12)).buffer - const additionalData = utf8.toBytes(this.#type) + const additionalData = utf8.toBytes(this.type) const encoded = new Uint8Array([...seed, ...mnemonic]) return crypto.subtle.encrypt({ name: 'AES-GCM', iv, additionalData }, key, encoded) .then(encrypted => { @@ -424,7 +424,7 @@ export class VaultWorker { /** * Parse inbound message from main thread into typechecked variables. */ - static #extractData (message: unknown) { + static _extractData (message: unknown) { try { // Message itself if (message == null) { @@ -479,7 +479,7 @@ export class VaultWorker { : crypto.getRandomValues(new Uint8Array(32)).buffer // CryptoKey from password, decryption key if unlocking else encryption key - return this.#createAesKey(action === 'unlock' ? 'decrypt' : 'encrypt', keySalt, password) + return this._createAesKey(action === 'unlock' ? 'decrypt' : 'encrypt', keySalt, password) .then(key => { if (password?.detached === false) { new Uint8Array(password).fill(0) @@ -582,9 +582,9 @@ 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. */ - static #load (type?: 'BIP-44' | 'BLAKE2b', key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise> { + static _load (type?: 'BIP-44' | 'BLAKE2b', key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise> { try { - if (!this.#locked) { + if (!this.locked) { throw new Error('Wallet is in use') } if (key == null || keySalt == null) { @@ -612,13 +612,13 @@ export class VaultWorker { throw new RangeError('Seed for BLAKE2b wallet must be 32 bytes') } } - this.#type = type + this.type = type let seed: Promise if (secret instanceof ArrayBuffer) { if (type === 'BLAKE2b') { seed = Bip39.fromEntropy(new Uint8Array(secret)) .then(bip39 => { - this.#mnemonic = utf8.toBuffer(bip39.phrase ?? '') + this.mnemonic = utf8.toBuffer(bip39.phrase ?? '') return secret }) } else { @@ -627,7 +627,7 @@ export class VaultWorker { } else { seed = Bip39.fromPhrase(secret) .then(bip39 => { - this.#mnemonic = utf8.toBuffer(bip39.phrase ?? '') + this.mnemonic = utf8.toBuffer(bip39.phrase ?? '') const derive = type === 'BIP-44' ? bip39.toBip39Seed(mnemonicSalt ?? '') : Promise.resolve(bip39.toBlake2bSeed()) @@ -635,8 +635,8 @@ export class VaultWorker { }) } return seed.then(seed => { - this.#seed = seed - return this.#encryptWallet(key) + this.seed = seed + return this._encryptWallet(key) .then(({ iv, encrypted }) => { return { iv, salt: keySalt, encrypted } }) -- 2.47.3