Refuse a non-finite number where a text field coerces one #18

Merged
lilleman merged 9 commits from worktree-non-finite-text into main 2026-09-21 10:46:52 +02:00
2 changed files with 8 additions and 3 deletions
Showing only changes of commit faa5482c7a - Show all commits
+6 -1
View File
@@ -38,6 +38,11 @@ export function paramNumber(value: ParamValue | undefined, fallback: number): nu
return typeof value === 'number' ? value : fallback; return typeof value === 'number' ? value : fallback;
} }
/** Spells a refused value for the caller who wrote it; JSON spells NaN and the infinities `null`. */
export function valueText(value: unknown): string {
return typeof value === 'number' ? String(value) : JSON.stringify(value);
}
function outOfRange(buffer: Buffer, offset: number, needed: number): Error | undefined { function outOfRange(buffer: Buffer, offset: number, needed: number): Error | undefined {
if (offset < 0 || needed < 0 || offset + needed > buffer.length) { if (offset < 0 || needed < 0 || offset + needed > buffer.length) {
return new Error( return new Error(
@@ -50,7 +55,7 @@ function outOfRange(buffer: Buffer, offset: number, needed: number): Error | und
function wantInt(value: ParamValue, max: number): Result<{ int: number }> { function wantInt(value: ParamValue, max: number): Result<{ int: number }> {
if (typeof value !== 'number' || !Number.isInteger(value)) { if (typeof value !== 'number' || !Number.isInteger(value)) {
return { err: new Error(`Expected an integer, got ${JSON.stringify(value)}`) }; return { err: new Error(`Expected an integer, got ${valueText(value)}`) };
} }
if (value < 0 || value > max) { if (value < 0 || value > max) {
+2 -2
View File
@@ -9,7 +9,7 @@ import { cmds, commandNameById, respNameFor } from './defs/commands.ts';
import { hasUdh } from './defs/constants.ts'; import { hasUdh } from './defs/constants.ts';
import { decodeMessage, encodeBody } from './message.ts'; import { decodeMessage, encodeBody } from './message.ts';
import { errorNameById, errors, isErrorName } from './defs/errors.ts'; import { errorNameById, errors, isErrorName } from './defs/errors.ts';
import { paramNumber } from './defs/types.ts'; import { paramNumber, valueText } from './defs/types.ts';
import { tagIdOf, tlvDefault, tlvs, tlvsById, writeTlvs } from './defs/tlvs.ts'; import { tagIdOf, tlvDefault, tlvs, tlvsById, writeTlvs } from './defs/tlvs.ts';
/** The highest sequence number this library hands out; SMPP 3.4 4.7.1 reserves 0x7fffffff. */ /** The highest sequence number this library hands out; SMPP 3.4 4.7.1 reserves 0x7fffffff. */
@@ -234,7 +234,7 @@ function buildPdu(
} }
if (!Number.isInteger(seqNr) || seqNr < 0 || seqNr > maxWireSeqNr) { if (!Number.isInteger(seqNr) || seqNr < 0 || seqNr > maxWireSeqNr) {
return { err: new Error(`Invalid seqNr: ${JSON.stringify(seqNr)}`) }; return { err: new Error(`Invalid seqNr: ${valueText(seqNr)}`) };
} }
const built = buildBody(definition, cmdName, cmdStatus, params, tlvs); const built = buildBody(definition, cmdName, cmdStatus, params, tlvs);