NODE: if (this.#parentPort == null) setTimeout(() => listener(event), 0)
const data = this.#parseData(event.data)
const action = this.#parseAction(data)
- const config = this.#parseConfig(action, data)
const keySalt = this.#parseKeySalt(action, data)
Passkey.create(action, keySalt, data)
.then((key: CryptoKey | undefined): Promise<NamedData | void> => {
const type = this.#parseType(action, data)
const iv = this.#parseIv(action, data)
- const { seed, mnemonicPhrase, mnemonicSalt, index, encrypted, message } = this.#extractData(action, data)
+ const { seed, mnemonicPhrase, mnemonicSalt, index, encrypted, message, timeout } = this.#extractData(action, data)
switch (action) {
case 'STOP': {
BROWSER: close()
NODE: process.exit()
}
case 'config': {
- return this.config(config)
+ return this.config(timeout)
}
case 'create': {
return this.create(type, key, keySalt, mnemonicSalt)
* Configures vault settings. The wallet must be unlocked prior to
* configuration.
*/
- config (config: { [key: string]: unknown }): Promise<void> {
- if (typeof config.timeout === 'number') {
- this.#timeout = config.timeout
+ config (timeout?: number): Promise<void> {
+ try {
+ this.#timer?.pause()
+ if (this.#locked) {
+ throw new Error('Wallet is locked')
+ }
+ if (typeof timeout === 'number') {
+ if (timeout < 0) {
+ throw new RangeError('Timeout must be non-negative')
+ }
+ if (timeout > 600) {
+ throw new RangeError('Maximum timeout is 10 minutes')
+ }
+ this.#timeout = timeout * 1000
+ this.#timer = new VaultTimer(() => this.lock(), this.#timeout)
+ }
+ return Promise.resolve()
+ } catch (err) {
+ console.error(err)
+ this.#timer?.resume()
+ throw new Error('Failed to configure Vault', { cause: err })
}
- return Promise.resolve()
}
/**
: Blake2b.ckd(this.#seed, index)
return derive.then(prv => {
const pub = NanoNaCl.convert(new Uint8Array(prv))
- this.#timer = new VaultTimer(() => this.lock(), 120000)
+ this.#timer = new VaultTimer(() => this.lock(), this.#timeout)
return { index, publicKey: pub.buffer }
})
} catch (err) {
: Blake2b.ckd(this.#seed, index)
return derive.then(prv => {
const sig = NanoNaCl.detached(new Uint8Array(data), new Uint8Array(prv))
- this.#timer = new VaultTimer(() => this.lock(), 120000)
+ this.#timer = new VaultTimer(() => this.lock(), this.#timeout)
return { signature: sig.buffer }
})
} catch (err) {
this.#seed = seed
this.#mnemonic = mnemonic
this.#locked = false
- this.#timer = new VaultTimer(this.lock.bind(this), 120000)
+ this.#timer = new VaultTimer(this.lock.bind(this), this.#timeout)
BROWSER: postMessage('unlocked')
NODE: this.#parentPort?.postMessage('unlocked')
})
}
return WalletAesGcm.encrypt(this.#type, key, this.#seed, this.#mnemonic)
.then(({ iv, encrypted }) => {
- this.#timer = new VaultTimer(() => this.lock(), 120000)
+ this.#timer = new VaultTimer(() => this.lock(), this.#timeout)
return { iv, salt, encrypted }
})
} catch (err) {
: undefined
delete data.message
- return { seed, mnemonicPhrase, mnemonicSalt, encrypted, index, message }
+ // Vault configuration
+ if (action === 'config') {
+ if (data.timeout == null) {
+ throw new TypeError('Configuration not found')
+ }
+ if (typeof data.timeout !== 'number') {
+ throw new TypeError('Invalid timeout configuration')
+ }
+ }
+ const timeout = typeof data.timeout === 'number'
+ ? data.timeout
+ : undefined
+
+ return { seed, mnemonicPhrase, mnemonicSalt, encrypted, index, message, timeout }
} catch (err) {
console.error(err)
throw new Error('Failed to extract data', { cause: err })
return data.action
}
- // Action for configuring vault
- #parseConfig (action: string, data: { [key: string]: unknown }) {
- const config: any = {}
- if (action === 'config') {
- if (data.timeout != null) {
- config.timeout = data.timeout
- }
- }
- return config
- }
-
// Worker message data itself
#parseData (data: unknown) {
if (data == null) {