From: Chris Duncan Date: Thu, 2 Jul 2026 15:45:36 +0000 (-0700) Subject: Put byte typechecks in conversion module. X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=2cc6a9317d5efceb7b404c4dca2df5ab59b739ca;p=libnemo.git Put byte typechecks in conversion module. --- diff --git a/src/lib/convert/bytes.ts b/src/lib/convert/bytes.ts index 955543c..3f9b8e2 100644 --- a/src/lib/convert/bytes.ts +++ b/src/lib/convert/bytes.ts @@ -6,6 +6,18 @@ import { ALPHABET, HEXCHAR } from '../constants' const decoder: TextDecoder = new TextDecoder() export const bytes = Object.freeze({ + /** + * Type guard to narrow ArrayBufferLike to ArrayBuffer. + * + * @param {unknown} input - Variable to check + */ + assert (input: unknown): Bytes { + if (!(input instanceof Uint8Array && input.buffer instanceof ArrayBuffer)) { + throw TypeError('input is not Uint8Array') + } + return input as Bytes + }, + /** * Write zeroes to memory to erase bytes and then transfers the buffer to * render it inaccessible to any process. @@ -20,6 +32,16 @@ export const bytes = Object.freeze({ bytes.fill(0) }, + /** + * Type guard to narrow ArrayBufferLike to ArrayBuffer. + * + * @param {unknown} input - Variable to check + * @returns True if input is Uint8Array, else false + */ + is (input: unknown): input is Bytes { + return input instanceof Uint8Array && input.buffer instanceof ArrayBuffer + }, + /** * Convert a Uint8Aarray of bytes to a base32 string. * diff --git a/src/lib/crypto/blake2b.ts b/src/lib/crypto/blake2b.ts index fcd7528..18bfca7 100644 --- a/src/lib/crypto/blake2b.ts +++ b/src/lib/crypto/blake2b.ts @@ -1,6 +1,8 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later AND ISC +import { bytes } from '../convert' + const OUTBYTES_MIN = 1 const OUTBYTES_MAX = 64 const KEYBYTES_MIN = 1 @@ -32,10 +34,6 @@ const SIGMA: number[][] = [ [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3] ] -function isBytes (a: unknown): a is Bytes { - return a instanceof Uint8Array && a.buffer instanceof ArrayBuffer -} - /** * Implementation derived from blake2b@2.1.4. Copyright 2017 Emil Bay * (https://github.com/emilbayes/blake2b). See LICENSES/ISC.txt @@ -215,13 +213,13 @@ export class Blake2b { if (typeof length !== 'number' || length < OUTBYTES_MIN || length > OUTBYTES_MAX) { throw new TypeError(`length is required and must be a number between ${OUTBYTES_MIN}-${OUTBYTES_MAX}`) } - if (key !== undefined && (!isBytes(key) || key.length < KEYBYTES_MIN || key.length > KEYBYTES_MAX)) { + if (key !== undefined && (!bytes.is(key) || key.length < KEYBYTES_MIN || key.length > KEYBYTES_MAX)) { throw new RangeError(`key must be ${KEYBYTES_MIN}-${KEYBYTES_MAX} bytes`) } - if (salt !== undefined && (!isBytes(salt) || salt.length !== SALTBYTES)) { + if (salt !== undefined && (!bytes.is(salt) || salt.length !== SALTBYTES)) { throw new RangeError(`salt must be ${SALTBYTES} bytes`) } - if (personal !== undefined && (!isBytes(personal) || personal.length !== PERSONALBYTES)) { + if (personal !== undefined && (!bytes.is(personal) || personal.length !== PERSONALBYTES)) { throw new RangeError(`personal must be ${PERSONALBYTES} bytes`) } this.#blake2bInit(length, key, salt, personal) @@ -237,7 +235,7 @@ export class Blake2b { if (input instanceof ArrayBuffer) { input = new Uint8Array(input) } - if (!isBytes(input)) { + if (!bytes.is(input)) { throw new TypeError('input must be bytes') } this.#blake2bUpdate(input) diff --git a/src/lib/ledger/cache.ts b/src/lib/ledger/cache.ts index 8ffc885..11b4d3f 100644 --- a/src/lib/ledger/cache.ts +++ b/src/lib/ledger/cache.ts @@ -35,7 +35,7 @@ export async function _cache (transport: LedgerTransport, index: number = 0, blo const t = await transport.create(OPEN_TIMEOUT, LISTEN_TIMEOUT) const response = await t .send(APDU_CODES.class, APDU_CODES.cacheBlock, APDU_CODES.paramUnused, APDU_CODES.paramUnused, data as Buffer) - .then((res: Buffer) => bytes.toDec(res)) + .then((res: Buffer) => bytes.toDec(bytes.assert(res))) .catch((err: any) => err.statusCode) .finally(async () => await t.close()) as number diff --git a/src/lib/ledger/close.ts b/src/lib/ledger/close.ts index 3a729cb..be819cc 100644 --- a/src/lib/ledger/close.ts +++ b/src/lib/ledger/close.ts @@ -1,14 +1,14 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { LedgerResponse, LedgerTransport, OPEN_TIMEOUT, LISTEN_TIMEOUT, APDU_CODES, STATUS_CODES } from '.' +import { APDU_CODES, LedgerResponse, LedgerTransport, LISTEN_TIMEOUT, OPEN_TIMEOUT, STATUS_CODES } from '.' import { bytes } from '../convert' export async function _close (transport: LedgerTransport): Promise { const t = await transport.create(OPEN_TIMEOUT, LISTEN_TIMEOUT) const response = await t .send(0xb0, 0xa7, APDU_CODES.paramUnused, APDU_CODES.paramUnused) - .then((res: Buffer) => bytes.toDec(res)) + .then((res: Buffer) => bytes.toDec(bytes.assert(res))) .catch((err: any) => err.statusCode) .finally(async () => await t.close()) as number return new Promise(r => setTimeout(r, 1000, { status: STATUS_CODES[response] })) diff --git a/src/lib/ledger/open.ts b/src/lib/ledger/open.ts index 1e6023b..52effa8 100644 --- a/src/lib/ledger/open.ts +++ b/src/lib/ledger/open.ts @@ -1,7 +1,7 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { LedgerResponse, LedgerTransport, OPEN_TIMEOUT, LISTEN_TIMEOUT, APDU_CODES, STATUS_CODES } from '.' +import { APDU_CODES, LedgerResponse, LedgerTransport, LISTEN_TIMEOUT, OPEN_TIMEOUT, STATUS_CODES } from '.' import { bytes } from '../convert' export async function _open (transport: LedgerTransport): Promise { @@ -9,7 +9,7 @@ export async function _open (transport: LedgerTransport): Promise bytes.toDec(res)) + .then((res: Buffer) => bytes.toDec(bytes.assert(res))) .catch((err: any) => err.statusCode) .finally(async () => await t.close()) as number return new Promise(r => setTimeout(r, 1000, { status: STATUS_CODES[response] }))