taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit a3c05d81871fc6cbf003fcdb71b3464dba2c4b4b
parent 8a50f1f167f7f8177a0fa0e2630d744d33c94597
Author: Florian Dold <dold@taler.net>
Date:   Tue, 21 Jul 2026 01:24:33 +0200

util: test codecForMap and union decoding of malformed input

Diffstat:
Mpackages/taler-util/src/codec.test.ts | 35+++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+), 0 deletions(-)

diff --git a/packages/taler-util/src/codec.test.ts b/packages/taler-util/src/codec.test.ts @@ -25,7 +25,10 @@ import { buildCodecForObject, codecForConstString, codecForString, + codecForNumber, + codecForMap, buildCodecForUnion, + DecodingError, } from "./codec.js"; interface MyObj { @@ -77,3 +80,35 @@ test("union", (t) => { assert.strictEqual(res.foo, "bla"); } }); + +test("codecForMap rejects arrays and prototype keys", (t) => { + const c = codecForMap(codecForString()); + // An array is not a map, though typeof [] === "object". + assert.throws(() => c.decode(["a", "b"])); + // "__proto__" used to invoke the prototype setter instead of creating an + // own property, so the key vanished and the prototype was attacker + // controlled. + const r = c.decode(JSON.parse('{"__proto__":"x","real":"z"}')); + assert.deepStrictEqual(Object.keys(r).sort(), ["__proto__", "real"]); + assert.strictEqual(Object.getPrototypeOf(r), Object.prototype); +}); + +test("union codec reports a decoding error for null", (t) => { + const c = buildCodecForUnion<{ type: "a"; n: number }>() + .discriminateOn("type") + .alternative( + "a", + buildCodecForObject<{ type: "a"; n: number }>() + .property("type", codecForConstString("a")) + .property("n", codecForNumber()) + .build("A"), + ) + .build("U"); + for (const bad of [null, undefined, 42, "str"]) { + assert.throws( + () => c.decode(bad), + (e: any) => e instanceof DecodingError, + `decoding ${JSON.stringify(bad)} should raise a DecodingError`, + ); + } +});