From 867c7080d718ebf6122291579b980f80f079721b Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sun, 9 Aug 2026 21:29:27 -0700 Subject: [PATCH] Solidify vault timer implementation. --- src/lib/vault/vault-timer.ts | 21 +++++++++++++++++++++ src/lib/vault/vault-worker.ts | 33 +++++++++++++++++---------------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/lib/vault/vault-timer.ts b/src/lib/vault/vault-timer.ts index bbde2b7..0bfe634 100644 --- a/src/lib/vault/vault-timer.ts +++ b/src/lib/vault/vault-timer.ts @@ -1,6 +1,11 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later +/** + * Executes a function after a timeout, with additional controls to manage the + * timer. Note: `this.#ticker` is a no-op every second in order to keep the + * timer from being put to sleep by the system. + */ export class VaultTimer { #f: () => any #isPaused: boolean = false @@ -27,6 +32,14 @@ export class VaultTimer { } } + reset (t: number) { + this.stop() + this.#remaining = t + this.#start = performance.now() + this.#ticker = setInterval(Function.prototype, 1000) + this.#timeout = setTimeout(this.#f, this.#remaining) + } + resume () { if (this.#isPaused) { this.#start = performance.now() @@ -35,4 +48,12 @@ export class VaultTimer { this.#isPaused = false } } + + stop () { + clearTimeout(this.#timeout) + clearInterval(this.#ticker) + this.#remaining = 0 + this.#start = 0 + this.#isPaused = false + } } diff --git a/src/lib/vault/vault-worker.ts b/src/lib/vault/vault-worker.ts index e326e7a..1bf5b19 100644 --- a/src/lib/vault/vault-worker.ts +++ b/src/lib/vault/vault-worker.ts @@ -16,7 +16,7 @@ import { VaultTimer } from './vault-timer' let _locked: boolean = true let _timeout: number = 120_000 -let _timer: VaultTimer = new VaultTimer(() => { }, 0) +let _timer: VaultTimer = new VaultTimer(_autolock, _timeout) let _type: 'BIP-44' | 'BLAKE2b' | 'Exodus' | undefined = undefined let _id: UUID | undefined = undefined let _seed: ArrayBuffer | undefined = undefined @@ -128,24 +128,25 @@ NODE: parentPort?.on('message', listener) */ function config (timeout?: number): Promise { try { - _timer?.pause() + _timer.pause() if (_locked) { throw new VaultError('Wallet is locked') } - if (typeof timeout === 'number') { - if (timeout < 10) { - throw new VaultError('Timeout must be at least 10 seconds') - } - if (timeout > 600) { - throw new VaultError('Timeout must be at most 10 minutes') - } - _timeout = timeout * 1000 - _timer = new VaultTimer(_autolock, _timeout) + if (typeof timeout !== 'number') { + throw new TypeError('Invalid timeout period', { cause: timeout }) } + if (timeout < 10) { + throw new VaultError('Timeout must be at least 10 seconds') + } + if (timeout > 600) { + throw new VaultError('Timeout must be at most 10 minutes') + } + _timeout = timeout * 1000 + _timer.reset(_timeout) return Promise.resolve() } catch (err) { console.error(err) - _timer?.resume() + _timer.resume() throw new VaultError('Failed to configure Vault', { cause: err }) } } @@ -219,7 +220,7 @@ function derive (index?: number | Uint32Array): Promise { @@ -299,7 +300,7 @@ function sign (index?: Uint32Array, data?: ArrayBuffer): Promise { @@ -355,7 +356,7 @@ function unlock (type?: WalletType, id?: UUID, key?: CryptoKey, iv?: ArrayBuffer _seed = seed _mnemonic = mnemonic _locked = false - _timer = new VaultTimer(_autolock, _timeout) + _timer.reset(_timeout) return Promise.resolve({ isLocked: false }) }) .catch(err => { @@ -389,7 +390,7 @@ function update (key?: CryptoKey, salt?: ArrayBuffer): Promise { - _timer = new VaultTimer(_autolock, _timeout) + _timer.reset(_timeout) return { iv, salt, encrypted } }) .catch(err => { -- 2.52.0