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:
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`,
+ );
+ }
+});