From: Chris Duncan Date: Mon, 11 Aug 2025 13:33:15 +0000 (-0700) Subject: Update JSdoc for sign methods. Remove output option for sign method and just referenc... X-Git-Tag: v0.10.5~41^2~119 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=8275b8ed7b522ca68793f3046347365f1f5847be;p=libnemo.git Update JSdoc for sign methods. Remove output option for sign method and just reference block property to reduce redundancy. Type check arguments. --- diff --git a/src/lib/block.ts b/src/lib/block.ts index 2566ab5..b57946d 100644 --- a/src/lib/block.ts +++ b/src/lib/block.ts @@ -378,7 +378,8 @@ export class Block { /** * Sets the `signature` property of the block to a precalculated value. * - * @param {string} [key] - 64-byte hexadecimal signature + * @param {string} signature - 64-byte hexadecimal signature + * @returns Block with `signature` value set */ sign (signature: string): Block /** @@ -386,18 +387,10 @@ export class Block { * the `signature` property of the block. * * @param {string} [key] - 32-byte hexadecimal private key to use for signing + * @returns Block with `signature` value set */ async sign (key: string): Promise /** - * Signs the block using a Wallet. If successful, the result is stored in - * the `signature` property of the block. The wallet must be unlocked prior to - * signing. - * - * @param {Wallet} wallet - Wallet to use for signing - * @param {number} index - Account in wallet to use for signing - */ - async sign (wallet: Wallet, index: number): Promise - /** * Signs the block using a Ledger hardware wallet. If that fails, an error is * thrown with the status code from the device. If successful, the result is * stored in the `signature` property of the block. The wallet must be unlocked @@ -405,8 +398,19 @@ export class Block { * * @param {number} index - Account index between 0x0 and 0x7fffffff * @param {object} [frontier] - JSON of frontier block for offline signing + * @returns Block with `signature` value set */ async sign (index: number, frontier?: Block): Promise + /** + * Signs the block using a Wallet. If successful, the result is stored in + * the `signature` property of the block. The wallet must be unlocked prior to + * signing. + * + * @param {Wallet} wallet - Wallet to use for signing + * @param {number} index - Account in wallet to use for signing + * @returns Block with `signature` value set + */ + async sign (wallet: Wallet, index: number): Promise sign (input: unknown, param?: unknown): Block | Promise { if (typeof input === 'string' && /^[A-F0-9]{128}$/.test(input)) { this.signature = input @@ -414,14 +418,14 @@ export class Block { } return new Promise(async (resolve, reject) => { try { - if (typeof input !== 'number' && typeof input !== 'string' && !(input instanceof Wallet)) { + if (typeof input === 'string' && /^[A-F0-9]{64}$/.test(input)) { + const signature = await NanoNaCl.detached(this.#hash(), hex.toBytes(input)) + this.signature = bytes.toHex(signature) + } else if (typeof input !== 'number' && typeof input !== 'string' && !(input instanceof Wallet)) { throw new TypeError('Invalid signing input') - } else if (typeof input === 'string' && /^[A-F0-9]{64}$/.test(input)) { - const sig = await NanoNaCl.detached(this.#hash(), hex.toBytes(input)) - this.signature = bytes.toHex(sig) } else if (input instanceof Wallet && typeof param === 'number') { const wallet = input - await wallet.sign(param, this, 'hex') + await wallet.sign(param, this) } else if (typeof input === 'number') { const index = input const { Ledger } = await import('./wallet/ledger') @@ -434,9 +438,9 @@ export class Block { console.warn('Error updating Ledger cache of previous block, attempting signature anyway', err) } } - this.signature = await ledger.sign(index, this, 'hex') + await ledger.sign(index, this) } else { - throw new TypeError('invalid key for block signature', { cause: typeof input }) + throw new TypeError('Invalid key for block signature', { cause: typeof input }) } resolve(this) } catch (err) { diff --git a/src/lib/wallet/index.ts b/src/lib/wallet/index.ts index 60d406e..b03275a 100644 --- a/src/lib/wallet/index.ts +++ b/src/lib/wallet/index.ts @@ -336,31 +336,24 @@ export class Wallet { * * @param {number} index - Account to use for signing * @param {(Block)} block - Block data to be hashed and signed - * @returns {Promise} Hexadecimal-formatted 64-byte signature */ - async sign (index: number, block: Block): Promise> - /** - * Signs a block using the private key of the account at the wallet index - * specified. The signature is appended to the signature field of the block - * before being returned. The wallet must be unlocked prior to signing. - * - * @param {number} index - Account to use for signing - * @param {(Block)} block - Block data to be hashed and signed - * @returns {Promise} Hexadecimal-formatted 64-byte signature - */ - async sign (index: number, block: Block, format: 'hex'): Promise - async sign (index: number, block: Block, format?: 'hex'): Promise> { + async sign (index: number, block: Block): Promise + async sign (index: unknown, block: unknown): Promise { try { + if (typeof index !== 'number') { + throw new TypeError('Index must be a number', { cause: index }) + } + if (!(block instanceof Block)) { + throw new TypeError('Invalid Block', { cause: block }) + } const { signature } = await this.#vault.request({ action: 'sign', index, data: hex.toBuffer(block.hash) }) - const sig = new Uint8Array(signature) - block.signature = bytes.toHex(sig) + block.signature = bytes.toHex(new Uint8Array(signature)) clearTimeout(this.#lockTimer) this.#lockTimer = setTimeout(() => this.lock(), 300000) - return format === 'hex' ? block.signature : sig } catch (err) { throw new Error(`Failed to sign block`, { cause: err }) } @@ -372,8 +365,12 @@ export class Wallet { * @param {string} password Used previously to lock the wallet * @returns True if successfully unlocked */ - async unlock (password: string): Promise { + async unlock (password: string): Promise + async unlock (password: unknown): Promise { try { + if (typeof password !== 'string') { + throw new TypeError('Password must be a string') + } const { iv, salt, encrypted } = await Wallet.#get(this.#id) const { isUnlocked } = await this.#vault.request({ action: 'unlock', diff --git a/src/lib/wallet/ledger.ts b/src/lib/wallet/ledger.ts index 661a3d3..b337bb9 100644 --- a/src/lib/wallet/ledger.ts +++ b/src/lib/wallet/ledger.ts @@ -262,41 +262,40 @@ export class Ledger extends Wallet { * Sign a block with the Ledger device. * * @param {number} index - Account number - * @param {object} block - Block data to sign - * @returns {Promise} Signature + * @param {Block} block - Block data to sign + * @param {Block} [frontier] - Previous block data to cache in the device */ - async sign (index: number, block: Block): Promise> - /** - * Sign a block with the Ledger device. - * - * @param {number} index - Account number - * @param {object} block - Block data to sign - * @returns {Promise} Signature - */ - async sign (index: number, block: Block, format?: 'hex', frontier?: Block): Promise - async sign (index: number, block: Block, format?: 'hex', frontier?: Block): Promise> { - if (typeof index !== 'number' || index < 0 || index >= HARDENED_OFFSET) { - throw new TypeError('Invalid account index') - } - if (frontier != null) { - const { status } = await this.#cacheBlock(index, frontier) + async sign (index: number, block: Block, frontier?: Block): Promise + async sign (index: number, block: Block, frontier?: Block): Promise { + try { + if (typeof index !== 'number') { + throw new TypeError('Index must be a number', { cause: index }) + } + if (index < 0 || index >= HARDENED_OFFSET) { + throw new RangeError(`Index outside allowed range 0-${HARDENED_OFFSET}`, { cause: index }) + } + if (frontier != null) { + const { status } = await this.#cacheBlock(index, frontier) + if (status !== 'OK') { + throw new Error('Failed to cache frontier block in ledger', { cause: status }) + } + } + console.log('Waiting for signature confirmation on Ledger device...') + const { status, signature, hash } = await this.#signBlock(index, block) if (status !== 'OK') { - throw new Error('failed to cache frontier block in ledger', { cause: status }) + throw new Error('Signing with ledger failed', { cause: status }) } + if (hash !== block.hash) { + throw new Error('Hash from ledger does not match hash from block', { cause: `${hash} | ${block.hash}` }) + } + if (signature == null) { + throw new Error('Ledger silently failed to return signature') + } + block.signature = signature + } catch (err) { + console.error(err) + throw new Error('Failed to sign block with Ledger', { cause: err }) } - console.log('Waiting for signature confirmation on Ledger device...') - const { status, signature, hash } = await this.#signBlock(index, block) - if (status !== 'OK') { - throw new Error('signing with ledger failed', { cause: status }) - } - if (hash !== block.hash) { - throw new Error('hash from ledger does not match hash from block', { cause: `${hash} | ${block.hash}` }) - } - if (signature == null) { - throw new Error('ledger failed to return signature') - } - block.signature = signature - return format === 'hex' ? signature : hex.toBytes(signature) } /** @@ -372,10 +371,10 @@ export class Ledger extends Wallet { .sign(testWallet, 0) const testSendBlock = new Block(testAccount.address, '0', testOpenBlock.hash, testAccount.address) .send(testAccount.address, 0) - const testSignature = await testWallet.sign(0, testOpenBlock, 'hex') + await testWallet.sign(0, testOpenBlock) try { - const signature = await this.sign(0, testSendBlock, 'hex', testOpenBlock) - return signature === testSignature + await this.sign(0, testSendBlock, testOpenBlock) + return testSendBlock.signature === testOpenBlock.signature } catch (err) { throw new Error('Failed to verify wallet', { cause: err }) }