]> git.codecow.com Git - libnemo.git/commitdiff
Put byte typechecks in conversion module.
authorChris Duncan <chris@codecow.com>
Thu, 2 Jul 2026 15:45:36 +0000 (08:45 -0700)
committerChris Duncan <chris@codecow.com>
Thu, 2 Jul 2026 15:45:36 +0000 (08:45 -0700)
src/lib/convert/bytes.ts
src/lib/crypto/blake2b.ts
src/lib/ledger/cache.ts
src/lib/ledger/close.ts
src/lib/ledger/open.ts

index 955543c16f4f751d059ca3f7290b76d8a95314ed..3f9b8e207c436c29bfe1616d1d3b045e03244535 100644 (file)
@@ -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<ArrayBuffer>')
+               }
+               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<ArrayBuffer>, 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.
         *
index fcd7528fe505228d72289224b0edda50a6b98bb5..18bfca7de60449f2b6635989aa9088345e7c8e2a 100644 (file)
@@ -1,6 +1,8 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
 //! 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
  * <github@tixz.dk> (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)
index 8ffc885a53c14af98f2fe459433f594009628d26..11b4d3f5700589d4dbfb0aae95229e6959795310 100644 (file)
@@ -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
 
index 3a729cb2e41d7da2c866928955bafb03908f1245..be819cce71f9df3f06e30f88cffec6e0d2f23682 100644 (file)
@@ -1,14 +1,14 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
 //! 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<LedgerResponse> {
        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] }))
index 1e6023b7568b08906516004ae79c6d679d15e543..52effa821e203e0f40507ac42d10a0b870e9ec71 100644 (file)
@@ -1,7 +1,7 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
 //! 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<LedgerResponse> {
@@ -9,7 +9,7 @@ export async function _open (transport: LedgerTransport): Promise<LedgerResponse
        const t = await transport.create(OPEN_TIMEOUT, LISTEN_TIMEOUT)
        const response = await t
                .send(0xe0, 0xd8, APDU_CODES.paramUnused, APDU_CODES.paramUnused, name 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
        return new Promise(r => setTimeout(r, 1000, { status: STATUS_CODES[response] }))