#job?: Task
#isIdle: boolean
+ #isLocked: boolean
#isTerminated: boolean
#queue: Task[] = []
#url: string
constructor () {
this.#isIdle = true
+ this.#isLocked = true
this.#isTerminated = false
this.#queue = []
this.#url = URL.createObjectURL(new Blob([blob], { type: 'text/javascript' }))
Vault.#instances.push(this)
}
+ get isLocked (): boolean { return this.#isLocked }
+
request<T extends Data> (data: NamedData): Promise<NamedData<T>> {
return new Promise((resolve, reject): void => {
if (this.#isTerminated) {
}
#report (results: any): void {
+ if (results === 'locked' || results === 'unlocked') {
+ this.#isLocked = results === 'locked'
+ return
+ }
if (this.#job == null) {
throw new Error('Worker returned results but had nowhere to report it.')
}
const { resolve, reject } = this.#job
try {
- if (results.error != null) {
+ if (results?.error != null) {
reject(results)
} else {
resolve(results)
#elapsed: number = 0
#isPaused: boolean = false
#start: number
+ #ticker: number | NodeJS.Timeout
#timeout: number | NodeJS.Timeout
constructor (f: () => any, t: number) {
+ this.#ticker = setInterval(() => { }, 1000)
this.#f = f
this.#start = performance.now()
- this.#timeout = setTimeout(f, t)
+ this.#timeout = setTimeout(this.#f, t)
}
pause () {
if (!this.#isPaused) {
+ clearInterval(this.#ticker)
clearTimeout(this.#timeout)
this.#elapsed = performance.now() - this.#start
this.#isPaused = true
resume () {
if (this.#isPaused) {
+ this.#ticker = setInterval(() => { }, 1000)
this.#start = performance.now()
this.#timeout = setTimeout(this.#f, this.#elapsed)
this.#isPaused = false
const action = this.#parseAction(data)
const keySalt = this.#parseKeySalt(action, data)
Passkey.create(action, keySalt, data)
- .then((key: CryptoKey | undefined): Promise<NamedData> => {
+ .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)
})
.then(result => {
const transfer = []
- for (const k of Object.keys(result)) {
- if (result[k] instanceof ArrayBuffer || result[k] instanceof CryptoKey) {
- transfer.push(result[k])
+ if (result) {
+ for (const k of Object.keys(result)) {
+ if (result[k] instanceof ArrayBuffer || result[k] instanceof CryptoKey) {
+ transfer.push(result[k])
+ }
}
}
//@ts-expect-error
.finally(() => this.lock())
}
- lock (): NamedData<boolean> {
+ lock (): void {
this.#mnemonic = undefined
this.#seed = undefined
this.#locked = true
this.#timeout?.pause()
- return { isLocked: this.#locked }
+ BROWSER: postMessage('locked')
+ NODE: this.#parentPort?.postMessage('locked')
}
/**
/**
* Decrypts the input and sets the seed and, if it is included, the mnemonic.
*/
- unlock (type?: string, key?: CryptoKey, iv?: ArrayBuffer, encrypted?: ArrayBuffer): Promise<NamedData<boolean>> {
+ unlock (type?: string, key?: CryptoKey, iv?: ArrayBuffer, encrypted?: ArrayBuffer): Promise<void> {
if (type == null) {
throw new TypeError('Wallet type is required')
}
this.#seed = seed
this.#mnemonic = mnemonic
this.#locked = false
- this.#timeout = new VaultTimer(() => this.lock(), 120000)
- return { isUnlocked: !this.#locked }
+ this.#timeout = new VaultTimer(this.lock.bind(this), 120000)
+ BROWSER: postMessage('unlocked')
+ NODE: this.#parentPort?.postMessage('unlocked')
})
.catch(err => {
console.error(err)
*/\r
get id (): string { return this.#id }\r
\r
+ /**\r
+ * @returns True if the wallet is locked, else false\r
+ */\r
+ get isLocked (): boolean {\r
+ return this.#vault.isLocked\r
+ }\r
+\r
/**\r
* Algorithm or device used to create wallet and derive accounts.\r
*/\r
}
})
} else {
- const { isLocked } = await vault.request<boolean>({
+ await vault.request({
action: 'lock'
})
- if (!isLocked) {
+ if (!wallet.isLocked) {
throw new Error('Lock request to Vault failed')
}
}
throw new TypeError('Password must be a string')
}
const { iv, salt, encrypted } = await _get(wallet.id)
- const { isUnlocked } = await vault.request<boolean>({
+ await vault.request({
action: 'unlock',
type: wallet.type,
password: utf8.toBuffer(password),
keySalt: salt,
encrypted
})
- if (!isUnlocked) {
+ if (wallet.isLocked) {
throw new Error('Unlock request to Vault failed')
}
}
*/
get id (): string
/**
+ * @returns True if the wallet is locked, else false
+ */
+ get isLocked (): boolean
+ /**
* Algorithm or device used to create wallet and derive accounts.
*/
get type (): WalletType
await assert.resolves(wallet.destroy())\r
})\r
\r
- await test('wallet automatic lock resets after user activity', { skip: true }, async () => {\r
+ await test('wallet automatic lock resets after user activity', { skip: false }, async () => {\r
+ console.log('Starting autolock test...')\r
const wallet = await Wallet.load('BIP-44', NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.MNEMONIC, NANO_TEST_VECTORS.PASSWORD)\r
+ assert.equal(wallet.isLocked, true)\r
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)\r
+ assert.equal(wallet.isLocked, false)\r
\r
assert.ok(await wallet.verify(NANO_TEST_VECTORS.MNEMONIC))\r
assert.ok(await wallet.verify(NANO_TEST_VECTORS.BIP39_SEED))\r
console.log('Waiting 1 minute...')\r
setTimeout(async () => {\r
// should still be unlocked\r
+ assert.equal(wallet.isLocked, false)\r
const account = await wallet.account(0)\r
assert.equal(account.address, NANO_TEST_VECTORS.ADDRESS_0)\r
resolve(null)\r
console.log('Timer should be reset, waiting 1 minute...')\r
setTimeout(async () => {\r
// should still be unlocked from account() reset and not initial unlock\r
+ assert.equal(wallet.isLocked, false)\r
assert.ok(await wallet.verify(NANO_TEST_VECTORS.MNEMONIC))\r
assert.ok(await wallet.verify(NANO_TEST_VECTORS.BIP39_SEED))\r
resolve(null)\r
console.log('Timer should not be reset by verify, waiting 1 minute...')\r
setTimeout(async () => {\r
// should be locked from account() reset and not reset by verify()\r
+ assert.equal(wallet.isLocked, true)\r
await assert.rejects(wallet.verify(NANO_TEST_VECTORS.MNEMONIC))\r
await assert.rejects(wallet.verify(NANO_TEST_VECTORS.BIP39_SEED))\r
await assert.resolves(wallet.destroy())\r