mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-08-13 22:37:29 +00:00
fix(ans): reject non-hex input in fromHex instead of silently decoding to 0 (#91)
fromHex validated only that the string was even-length, then used
parseInt(pair, 16) per byte. parseInt returns NaN for a non-hex pair, and a
Uint8Array stores NaN as 0 — so fromHex('zzzz') silently returned [0, 0]
instead of failing. Add a hex-charset check (allowing empty input) so bad
input throws. Add bytes.test.ts covering valid decode, round-trip, odd-length
and non-hex cases.
This commit is contained in:
parent
7d62e3b661
commit
8107140228
2 changed files with 30 additions and 0 deletions
27
packages/ans/src/bytes.test.ts
Normal file
27
packages/ans/src/bytes.test.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { fromHex, toHex } from './bytes.js';
|
||||||
|
|
||||||
|
describe('fromHex', () => {
|
||||||
|
it('decodes valid hex, with and without 0x prefix', () => {
|
||||||
|
expect([...fromHex('00ff10')]).toEqual([0x00, 0xff, 0x10]);
|
||||||
|
expect([...fromHex('0xdeadbeef')]).toEqual([0xde, 0xad, 0xbe, 0xef]);
|
||||||
|
expect([...fromHex('')]).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('round-trips with toHex', () => {
|
||||||
|
const bytes = Uint8Array.from([0, 1, 127, 128, 255]);
|
||||||
|
expect([...fromHex(toHex(bytes))]).toEqual([...bytes]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws on odd-length input', () => {
|
||||||
|
expect(() => fromHex('abc')).toThrow(/odd-length/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws on non-hex characters instead of silently decoding to 0', () => {
|
||||||
|
// Previously parseInt('zz', 16) === NaN, which a Uint8Array stores as 0,
|
||||||
|
// so fromHex('zzzz') silently returned [0, 0].
|
||||||
|
expect(() => fromHex('zzzz')).toThrow(/invalid hex/);
|
||||||
|
expect(() => fromHex('00gg')).toThrow(/invalid hex/);
|
||||||
|
expect(() => fromHex('0xnothex')).toThrow(/invalid hex/);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -26,6 +26,9 @@ export function toHex(bytes: Uint8Array): string {
|
||||||
export function fromHex(hex: string): Uint8Array {
|
export function fromHex(hex: string): Uint8Array {
|
||||||
const clean = hex.startsWith('0x') ? hex.slice(2) : hex;
|
const clean = hex.startsWith('0x') ? hex.slice(2) : hex;
|
||||||
if (clean.length % 2 !== 0) throw new Error('odd-length hex string');
|
if (clean.length % 2 !== 0) throw new Error('odd-length hex string');
|
||||||
|
// Reject non-hex input. Without this, parseInt returns NaN for a bad pair
|
||||||
|
// and the Uint8Array silently stores 0, producing wrong bytes.
|
||||||
|
if (!/^[0-9a-fA-F]*$/.test(clean)) throw new Error('invalid hex string');
|
||||||
const out = new Uint8Array(clean.length / 2);
|
const out = new Uint8Array(clean.length / 2);
|
||||||
for (let i = 0; i < out.length; i++) out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
for (let i = 0; i < out.length; i++) out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
||||||
return out;
|
return out;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue