diff --git a/encoding.go b/encoding.go index 0ca77af..133bdf9 100644 --- a/encoding.go +++ b/encoding.go @@ -30,10 +30,22 @@ func NewCBOREncoder(w io.Writer) Encoder { return cbor.NewEncoder(w) } +// Single ceiling for CBOR arrays and maps (fxamacker/cbor defaults are 131072 each). +const cborMaxDecodeElements = 500_000 + +type errDecoder struct{ err error } + +func (d errDecoder) Decode(v any) error { return d.err } + func NewCBORDecoder(r io.Reader) Decoder { opt := cbor.DecOptions{ - MaxNestedLevels: 1024, // Set the desired maximum nesting depth + MaxNestedLevels: 1024, + MaxArrayElements: cborMaxDecodeElements, + MaxMapPairs: cborMaxDecodeElements, + } + mode, err := opt.DecMode() + if err != nil { + return errDecoder{err} } - mode, _ := opt.DecMode() return mode.NewDecoder(r) } diff --git a/encoding_test.go b/encoding_test.go new file mode 100644 index 0000000..4ddeee5 --- /dev/null +++ b/encoding_test.go @@ -0,0 +1,44 @@ +package ethwal + +import ( + "bytes" + "testing" + + "github.com/fxamacker/cbor/v2" + "github.com/stretchr/testify/require" +) + +func TestNewCBORDecoderLargeArray(t *testing.T) { + const n = 131073 + s := make([]uint64, n) + for i := range s { + s[i] = uint64(i) + } + data, err := cbor.Marshal(s) + require.NoError(t, err) + + var out []uint64 + dec := NewCBORDecoder(bytes.NewReader(data)) + err = dec.Decode(&out) + require.NoError(t, err) + require.Len(t, out, n) +} + +func TestNewCBORDecoderLargeMap(t *testing.T) { + const n = 131073 + m := make(map[uint64]uint64, n) + for i := uint64(0); i < n; i++ { + m[i] = i + } + data, err := cbor.Marshal(m) + require.NoError(t, err) + + var out map[uint64]uint64 + dec := NewCBORDecoder(bytes.NewReader(data)) + err = dec.Decode(&out) + require.NoError(t, err) + require.Len(t, out, n) + require.Equal(t, uint64(0), out[0]) + require.Equal(t, uint64(n-1), out[n-1]) + require.Equal(t, uint64(n/2), out[n/2]) +}