From: Chris Duncan Date: Mon, 3 Aug 2026 17:55:38 +0000 (-0700) Subject: Fix hoisted process env var. Improve post action and data validation. X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=2400116b71c5ca6e14afe982d43c4f456e3f76bf;p=libnemo.git Fix hoisted process env var. Improve post action and data validation. --- diff --git a/src/lib/rpc/index.ts b/src/lib/rpc/index.ts index f299002..6bfcd6c 100644 --- a/src/lib/rpc/index.ts +++ b/src/lib/rpc/index.ts @@ -1,21 +1,22 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later +import { SCHEMA } from './schema' /** -* Represents a Nano network node. It primarily consists of a URL which will -* accept RPC calls, and an optional API key header construction can be passed if -* required by the node. Once instantiated, the Rpc object can be used to call -* any action supported by the Nano protocol. The URL protocol must be HTTPS; any -* other value will be changed automatically. -*/ + * Represents a Nano network node. It primarily consists of a URL which will + * accept RPC calls, and an optional API key header construction can be passed if + * required by the node. Once instantiated, the Rpc object can be used to call + * any action supported by the Nano protocol. The URL protocol must be HTTPS; any + * other value will be changed automatically. + */ export class Rpc { #u: URL #n?: string /** - * @param {(string|URL)} url - * @param {string} [apiKeyName] - */ + * @param {(string|URL)} url + * @param {string} [apiKeyName] + */ constructor (url: string | URL, apiKeyName?: string) { this.#u = new URL(url) this.#u.protocol = 'https:' @@ -23,31 +24,37 @@ export class Rpc { } /** - * Sends a nano RPC call to a node endpoint. - * - * @param {string} action - Nano protocol RPC call to execute - * @param {object} [data] - JSON to send to the node as defined by the action - * @returns {Promise} JSON-formatted RPC results from the node - */ - async post (action: string, data?: Record): Promise { - var process: any = process || null + * Sends a nano RPC call to a node endpoint. + * + * @param {string} action - Nano protocol RPC call to execute + * @param {object} [data] - JSON to send to the node as defined by the action + * @returns {Promise} JSON-formatted RPC results from the node + */ + async post (action: string, data?: Record): Promise + async post (action: unknown, data: unknown): Promise { + const env = typeof process !== 'undefined' && 'env' in process ? process.env : null this.#validate(action) + action = action.toLowerCase() const headers: Record = {} headers['Content-Type'] = 'application/json' - if (this.#n && process?.env?.LIBNEMO_RPC_API_KEY) { - headers[this.#n] = process.env.LIBNEMO_RPC_API_KEY + if (this.#n && env?.LIBNEMO_RPC_API_KEY) { + headers[this.#n] = env.LIBNEMO_RPC_API_KEY } - - data ??= {} - data.action = action.toLowerCase() - const body = JSON.stringify(data) + if (data !== undefined && typeof data !== 'object') { + throw new TypeError('Invalid RPC post data') + } + const body = (data as Record) ?? {} + if ('action' in body && (typeof body.action !== 'string' || body.action.toLowerCase() !== action)) { + throw new RangeError(`RPC post data contains 'action' property and does not match 'action' parameter argument. Do not include 'action' in request data.`) + } + body.action = action const aborter = new AbortController() const req = new Request(this.#u, { signal: aborter.signal, method: 'POST', headers, - body + body: JSON.stringify(body) }) const kill = setTimeout(() => { console.log('aborting RPC call') @@ -74,7 +81,7 @@ export class Rpc { } } - #validate (action: string): void { + #validate (action: unknown): asserts action is string { if (!action) { throw new ReferenceError('Action is required for RPCs') } @@ -84,5 +91,8 @@ export class Rpc { if (!/^[A-Za-z]+(_[A-Za-z]+)*$/.test(action)) { throw new TypeError('RPC action contains invalid characters') } + if (!(action in SCHEMA)) { + throw new TypeError('Unknown RPC action') + } } }