diff --git a/cmw.go b/cmw.go index cd515e9..593cf37 100644 --- a/cmw.go +++ b/cmw.go @@ -14,18 +14,19 @@ import ( type Serialization uint const ( - JSONArray = Serialization(iota) + UnknownSerialization = Serialization(iota) + JSONArray CBORArray CBORTag - Unknown ) // a CMW object holds the internal representation of a RATS conceptual message // wrapper type CMW struct { - typ Type - val Value - ind Indicator + typ Type + val Value + ind Indicator + serialization Serialization } func (o *CMW) SetMediaType(v string) { _ = o.typ.Set(v) } @@ -41,41 +42,55 @@ func (o *CMW) SetIndicators(indicators ...Indicator) { o.ind = v } +func (o *CMW) SetSerialization(s Serialization) { o.serialization = s } -func (o CMW) GetValue() []byte { return o.val } -func (o CMW) GetType() string { return o.typ.String() } -func (o CMW) GetIndicator() Indicator { return o.ind } +func (o CMW) GetValue() []byte { return o.val } +func (o CMW) GetType() string { return o.typ.String() } +func (o CMW) GetIndicator() Indicator { return o.ind } +func (o CMW) GetSerialization() Serialization { return o.serialization } // Deserialize a CMW func (o *CMW) Deserialize(b []byte) error { - switch sniff(b) { + s := sniff(b) + + o.serialization = s + + switch s { case JSONArray: return o.UnmarshalJSON(b) - case CBORArray: + case CBORArray, CBORTag: return o.UnmarshalCBOR(b) - case CBORTag: - return o.UnmarshalCBORTag(b) } + return errors.New("unknown CMW format") } -// Serialize a CMW according to the provided Serialization -func (o CMW) Serialize(s Serialization) ([]byte, error) { +// Serialize a CMW according to its provided Serialization +func (o CMW) Serialize() ([]byte, error) { + s := o.serialization switch s { case JSONArray: return o.MarshalJSON() - case CBORArray: + case CBORArray, CBORTag: return o.MarshalCBOR() - case CBORTag: - return o.MarshalCBORTag() } return nil, fmt.Errorf("invalid serialization format %d", s) } func (o CMW) MarshalJSON() ([]byte, error) { return arrayEncode(json.Marshal, &o) } -func (o CMW) MarshalCBOR() ([]byte, error) { return arrayEncode(cbor.Marshal, &o) } -func (o CMW) MarshalCBORTag() ([]byte, error) { +func (o CMW) MarshalCBOR() ([]byte, error) { + s := o.serialization + switch s { + case CBORArray: + return arrayEncode(cbor.Marshal, &o) + case CBORTag: + return o.encodeCBORTag() + } + return nil, fmt.Errorf("invalid serialization format: want CBORArray or CBORTag, got %d", s) +} + +func (o CMW) encodeCBORTag() ([]byte, error) { var ( tag cbor.RawTag err error @@ -99,14 +114,26 @@ func (o CMW) MarshalCBORTag() ([]byte, error) { } func (o *CMW) UnmarshalCBOR(b []byte) error { - return arrayDecode[cbor.RawMessage](cbor.Unmarshal, b, o) + if arrayDecode[cbor.RawMessage](cbor.Unmarshal, b, o) == nil { + o.serialization = CBORArray + return nil + } + + if o.decodeCBORTag(b) == nil { + // the serialization attribute is set by decodeCBORTag + return nil + } + + return errors.New("invalid CBOR-encoded CMW") } func (o *CMW) UnmarshalJSON(b []byte) error { - return arrayDecode[json.RawMessage](json.Unmarshal, b, o) + err := arrayDecode[json.RawMessage](json.Unmarshal, b, o) + o.serialization = JSONArray + return err } -func (o *CMW) UnmarshalCBORTag(b []byte) error { +func (o *CMW) decodeCBORTag(b []byte) error { var ( v cbor.RawTag m []byte @@ -123,13 +150,14 @@ func (o *CMW) UnmarshalCBORTag(b []byte) error { _ = o.typ.Set(v.Number) _ = o.val.Set(m) + o.serialization = CBORTag return nil } func sniff(b []byte) Serialization { if len(b) == 0 { - return Unknown + return UnknownSerialization } if b[0] == 0x82 || b[0] == 0x83 { @@ -140,12 +168,12 @@ func sniff(b []byte) Serialization { return JSONArray } - return Unknown + return UnknownSerialization } type ( - arrayDecoder func([]byte, interface{}) error - arrayEncoder func(interface{}) ([]byte, error) + arrayDecoder func([]byte, any) error + arrayEncoder func(any) ([]byte, error) ) func arrayDecode[V json.RawMessage | cbor.RawMessage]( @@ -185,7 +213,7 @@ func arrayEncode(enc arrayEncoder, o *CMW) ([]byte, error) { return nil, fmt.Errorf("type and value MUST be set in CMW") } - a := []interface{}{o.typ, o.val} + a := []any{o.typ, o.val} if !o.ind.Empty() { a = append(a, o.ind) diff --git a/cmw_test.go b/cmw_test.go index 20c56bb..7593fd1 100644 --- a/cmw_test.go +++ b/cmw_test.go @@ -84,6 +84,7 @@ func Test_Deserialize_ok(t *testing.T) { Type{uint16(30001)}, []byte{0xde, 0xad, 0xbe, 0xef}, IndicatorNone, + JSONArray, }, }, { @@ -93,6 +94,7 @@ func Test_Deserialize_ok(t *testing.T) { Type{"application/vnd.intel.sgx"}, []byte{0xde, 0xad, 0xbe, 0xef}, IndicatorNone, + JSONArray, }, }, { @@ -102,6 +104,7 @@ func Test_Deserialize_ok(t *testing.T) { Type{"application/vnd.intel.sgx"}, []byte{0xde, 0xad, 0xbe, 0xef}, testIndicator, + JSONArray, }, }, { @@ -112,6 +115,7 @@ func Test_Deserialize_ok(t *testing.T) { Type{uint16(30001)}, []byte{0xde, 0xad, 0xbe, 0xef}, IndicatorNone, + CBORArray, }, }, { @@ -127,6 +131,7 @@ func Test_Deserialize_ok(t *testing.T) { Type{string("application/vnd.intel.sgx")}, []byte{0xde, 0xad, 0xbe, 0xef}, IndicatorNone, + CBORArray, }, }, { @@ -139,6 +144,7 @@ func Test_Deserialize_ok(t *testing.T) { Type{uint64(1668576818)}, []byte{0xde, 0xad, 0xbe, 0xef}, IndicatorNone, + CBORTag, }, }, } @@ -203,8 +209,9 @@ func Test_Serialize_JSONArray_ok(t *testing.T) { cmw.SetMediaType(tt.tv.typ) cmw.SetValue(tt.tv.val) cmw.SetIndicators(tt.tv.ind...) + cmw.SetSerialization(JSONArray) - actual, err := cmw.Serialize(JSONArray) + actual, err := cmw.Serialize() assert.NoError(t, err) assert.JSONEq(t, tt.exp, string(actual)) }) @@ -259,8 +266,9 @@ func Test_Serialize_CBORArray_ok(t *testing.T) { cmw.SetContentFormat(tt.tv.typ) cmw.SetValue(tt.tv.val) cmw.SetIndicators(tt.tv.ind...) + cmw.SetSerialization(CBORArray) - actual, err := cmw.Serialize(CBORArray) + actual, err := cmw.Serialize() assert.NoError(t, err) assert.Equal(t, tt.exp, actual) }) @@ -310,8 +318,9 @@ func Test_Serialize_CBORTag_ok(t *testing.T) { cmw.SetTagNumber(tt.tv.typ) cmw.SetValue(tt.tv.val) + cmw.SetSerialization(CBORTag) - actual, err := cmw.Serialize(CBORTag) + actual, err := cmw.Serialize() assert.NoError(t, err) assert.Equal(t, tt.exp, actual) }) @@ -441,7 +450,7 @@ func Test_Deserialize_CBORArray_ko(t *testing.T) { 0x82, 0xfb, 0x40, 0x8f, 0x41, 0xd7, 0x0a, 0x3d, 0x70, 0xa4, 0x44, 0xde, 0xad, 0xbe, 0xef, }, - `unmarshaling type: cannot unmarshal 1000.230000 into uint16`, + `invalid CBOR-encoded CMW`, }, { "overflow for type", @@ -450,7 +459,7 @@ func Test_Deserialize_CBORArray_ko(t *testing.T) { 0x82, 0x1a, 0x00, 0x01, 0x00, 0x00, 0x44, 0xde, 0xad, 0xbe, 0xef, }, - `unmarshaling type: cannot unmarshal 65536 into uint16`, + `invalid CBOR-encoded CMW`, }, { "bad type (float) for value", @@ -459,7 +468,7 @@ func Test_Deserialize_CBORArray_ko(t *testing.T) { 0x82, 0x19, 0xff, 0xff, 0xfb, 0x3f, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, }, - `unmarshaling value: cannot decode value: cbor: cannot unmarshal primitives into Go value of type []uint8`, + `invalid CBOR-encoded CMW`, }, } @@ -481,13 +490,13 @@ func Test_Deserialize_CBORTag(t *testing.T) { { "empty CBOR Tag", []byte{0xda, 0x63, 0x74, 0x01, 0x01}, - `unmarshal CMW CBOR Tag bstr-wrapped value: EOF`, + `invalid CBOR-encoded CMW`, }, { "bad type (uint) for value", // echo "1668546817(1)" | diag2cbor.rb | xxd -i []byte{0xda, 0x63, 0x74, 0x01, 0x01, 0x01}, - `unmarshal CMW CBOR Tag bstr-wrapped value: cbor: cannot unmarshal positive integer into Go value of type []uint8`, + `invalid CBOR-encoded CMW`, }, } @@ -504,28 +513,42 @@ func Test_EncodeArray_sanitize_input(t *testing.T) { var cmw CMW for _, s := range []Serialization{CBORArray, JSONArray} { - _, err := cmw.Serialize(s) + cmw.SetSerialization(s) + _, err := cmw.Serialize() assert.EqualError(t, err, "type and value MUST be set in CMW") } cmw.SetValue([]byte{0xff}) for _, s := range []Serialization{CBORArray, JSONArray} { - _, err := cmw.Serialize(s) + cmw.SetSerialization(s) + _, err := cmw.Serialize() assert.EqualError(t, err, "type and value MUST be set in CMW") } cmw.SetMediaType("") for _, s := range []Serialization{CBORArray, JSONArray} { - _, err := cmw.Serialize(s) + cmw.SetSerialization(s) + _, err := cmw.Serialize() assert.EqualError(t, err, "type and value MUST be set in CMW") } cmw.SetContentFormat(0) for _, s := range []Serialization{CBORArray, JSONArray} { - _, err := cmw.Serialize(s) + cmw.SetSerialization(s) + _, err := cmw.Serialize() assert.NoError(t, err) } } + +func Test_Serialize_invalid_serialization(t *testing.T) { + var tv CMW + + tv.SetMediaType("application/vnd.x") + tv.SetValue([]byte{0x00}) + + _, err := tv.Serialize() + assert.Error(t, err, "TPDP") +} diff --git a/collection.go b/collection.go new file mode 100644 index 0000000..fbc0ae6 --- /dev/null +++ b/collection.go @@ -0,0 +1,200 @@ +// Copyright 2023 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package cmw + +import ( + "encoding/json" + "errors" + "fmt" + + "github.com/fxamacker/cbor/v2" +) + +type Collection struct { + m map[any]CMW +} + +type CollectionSerialization uint + +const ( + UnknownCollectionSerialization = CollectionSerialization(iota) + CollectionSerializationJSON + CollectionSerializationCBOR +) + +// Deserialize a JSON or CBOR collection +func (o *Collection) Deserialize(b []byte) error { + switch b[0] { + case 0x7b: // '{' + return o.UnmarshalJSON(b) + default: + return o.UnmarshalCBOR(b) + } +} + +// Serialize the collection. The type of serialization depends on the +// serialization specified for each item. Items must have compatible +// serializations: CBORArray/CBORTag or JSON. +func (o *Collection) Serialize() ([]byte, error) { + s, err := o.detectSerialization() + if err != nil { + return nil, err + } + + switch s { + case CollectionSerializationCBOR: + return o.MarshalCBOR() + case CollectionSerializationJSON: + return o.MarshalJSON() + default: + return nil, errors.New("unsupported serialization") + } +} + +// GetMap returns a pointer to the internal map +func (o *Collection) GetMap() map[any]CMW { + return o.m +} + +// GetItem returns the CMW associated with label k +func (o *Collection) GetItem(k any) (CMW, error) { + v, ok := o.m[k] + if !ok { + return CMW{}, fmt.Errorf("item not found for key %v", k) + } + return v, nil +} + +// AddItem adds a new item with label k to the collection +func (o *Collection) AddItem(k any, c CMW) { + if o.m == nil { + o.m = make(map[any]CMW) + } + o.m[k] = c +} + +// MarshalJSON serializes the collection to JSON +func (o Collection) MarshalJSON() ([]byte, error) { + m := make(map[string]json.RawMessage) + + for i, v := range o.m { + c, err := v.Serialize() + if err != nil { + return nil, fmt.Errorf("marshaling JSON collection item %v: %w", i, err) + } + switch t := i.(type) { + case string: + m[t] = c + default: + return nil, fmt.Errorf("JSON collection, key error: want string, got %T", t) + } + } + + b, err := json.Marshal(m) + if err != nil { + return nil, fmt.Errorf("marshaling JSON collection: %w", err) + } + + return b, nil +} + +// MarshalCBOR serializes the collection to CBOR +func (o Collection) MarshalCBOR() ([]byte, error) { + m := make(map[any]cbor.RawMessage) + + for i, v := range o.m { + c, err := v.Serialize() + if err != nil { + return nil, fmt.Errorf("marshaling CBOR collection item %v: %w", i, err) + } + switch t := i.(type) { + case string, uint64: + m[t] = c + default: + return nil, fmt.Errorf("CBOR collection, key error: want string or int64, got %T", t) + } + } + + b, err := cbor.Marshal(m) + if err != nil { + return nil, fmt.Errorf("marshaling CBOR collection: %w", err) + } + + return b, nil +} + +// UnmarshalCBOR unmarshal the supplied CBOR buffer to a CMW collection +func (o *Collection) UnmarshalCBOR(b []byte) error { + var tmp map[any]cbor.RawMessage + + if err := cbor.Unmarshal(b, &tmp); err != nil { + return fmt.Errorf("unmarshaling CBOR collection: %w", err) + } + + m := make(map[any]CMW) + + for k, v := range tmp { + var c CMW + if err := c.Deserialize(v); err != nil { + return fmt.Errorf("unmarshaling CBOR collection item %v: %w", k, err) + } + m[k] = c + } + + o.m = m + + return nil +} + +// UnmarshalJSON unmarshals the supplied JSON buffer to a CMW collection +func (o *Collection) UnmarshalJSON(b []byte) error { + var tmp map[string]json.RawMessage + + if err := json.Unmarshal(b, &tmp); err != nil { + return fmt.Errorf("unmarshaling JSON collection: %w", err) + } + + m := make(map[any]CMW) + + for k, v := range tmp { + var c CMW + if err := c.Deserialize(v); err != nil { + return fmt.Errorf("unmarshaling JSON collection item %v: %w", k, err) + } + m[k] = c + } + + o.m = m + + return nil +} + +func (o Collection) detectSerialization() (CollectionSerialization, error) { + rec := make(map[CollectionSerialization]bool) + + s := UnknownCollectionSerialization + + for k, v := range o.m { + switch v.serialization { + case CBORArray, CBORTag: + s = CollectionSerializationCBOR + rec[s] = true + case JSONArray: + s = CollectionSerializationJSON + rec[s] = true + default: + return UnknownCollectionSerialization, + fmt.Errorf( + "serialization not defined for collection item with k %v", k, + ) + } + } + + if len(rec) != 1 { + return UnknownCollectionSerialization, + errors.New("CMW collection has items with incompatible serializations") + } + + return s, nil +} diff --git a/collection_test.go b/collection_test.go new file mode 100644 index 0000000..b68f6b3 --- /dev/null +++ b/collection_test.go @@ -0,0 +1,187 @@ +// Copyright 2023 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package cmw + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func mustReadFile(t *testing.T, fname string) []byte { + b, err := os.ReadFile(fname) + require.NoError(t, err) + return b +} + +func Test_Collection_JSON_Deserialize_ok(t *testing.T) { + tv := mustReadFile(t, "testdata/collection-ok.json") + + var expectedA CMW + expectedA.SetMediaType("application/vnd.a") + expectedA.SetValue([]byte{0x61}) + expectedA.SetSerialization(JSONArray) + + var expectedB CMW + expectedB.SetMediaType("application/vnd.b") + expectedB.SetValue([]byte{0x62}) + expectedB.SetSerialization(JSONArray) + + var actual Collection + err := actual.UnmarshalJSON(tv) + assert.NoError(t, err) + + a, err := actual.GetItem("a") + assert.NoError(t, err) + assert.Equal(t, a, expectedA) + + b, err := actual.GetItem("b") + assert.NoError(t, err) + assert.Equal(t, b, expectedB) +} + +func Test_Collection_JSON_Serialize_ok(t *testing.T) { + expected := mustReadFile(t, "testdata/collection-ok.json") + + var tv Collection + + var a CMW + a.SetMediaType("application/vnd.a") + a.SetValue([]byte{0x61}) + a.SetSerialization(JSONArray) + + tv.AddItem("a", a) + + var b CMW + b.SetMediaType("application/vnd.b") + b.SetValue([]byte{0x62}) + b.SetSerialization(JSONArray) + + tv.AddItem("b", b) + + actual, err := tv.Serialize() + assert.NoError(t, err) + + assert.JSONEq(t, string(expected), string(actual)) +} + +func Test_Collection_JSON_Deserialize_fail_outer(t *testing.T) { + tv := []byte(`;rubbish json;`) + + var actual Collection + err := actual.UnmarshalJSON(tv) + assert.EqualError(t, err, `unmarshaling JSON collection: invalid character ';' looking for beginning of value`) +} + +func Test_Collection_JSON_Deserialize_fail_inner(t *testing.T) { + tv := []byte(`{ "a": {} }`) + + var actual Collection + err := actual.UnmarshalJSON(tv) + assert.EqualError(t, err, `unmarshaling JSON collection item a: unknown CMW format`) +} + +func Test_Collection_CBOR_Deserialize_ok(t *testing.T) { + tv := mustReadFile(t, "testdata/collection-cbor-ok.cbor") + + var actual Collection + err := actual.UnmarshalCBOR(tv) + assert.NoError(t, err) + + one, err := actual.GetItem(uint64(1)) + assert.NoError(t, err) + assert.Equal(t, "application/signed-corim+cbor", one.GetType()) + assert.Equal(t, []byte{0xd2, 0x84, 0x43, 0xa1, 0x1, 0x26, 0xa1}, one.GetValue()) + assert.Equal(t, Indicator(3), one.GetIndicator()) + assert.Equal(t, CBORArray, one.GetSerialization()) + + two, err := actual.GetItem(uint64(2)) + assert.NoError(t, err) + assert.Equal(t, "29884", two.GetType()) // TN() mapped CoAP C-F + assert.Equal(t, []byte{0x23, 0x47, 0xda, 0x55}, two.GetValue()) + assert.Equal(t, Indicator(0), two.GetIndicator()) + assert.Equal(t, CBORTag, two.GetSerialization()) + + s, err := actual.GetItem("s") + assert.NoError(t, err) + assert.Equal(t, "30001", s.GetType()) + assert.Equal(t, []byte{0x23, 0x47, 0xda, 0x55}, s.GetValue()) + assert.Equal(t, Indicator(0), s.GetIndicator()) + assert.Equal(t, CBORArray, s.GetSerialization()) +} + +func Test_Collection_CBOR_Serialize_ok(t *testing.T) { + var item1 CMW + item1.SetMediaType("application/vnd.1") + item1.SetValue([]byte{0xde, 0xad, 0xbe, 0xef}) + item1.SetSerialization(CBORArray) + + var tv Collection + tv.AddItem(uint64(1), item1) + + expected := mustReadFile(t, "testdata/collection-cbor-ok-2.cbor") + + b, err := tv.Serialize() + assert.NoError(t, err) + assert.Equal(t, expected, b) +} + +func Test_Collection_CBOR_Deserialize_and_iterate(t *testing.T) { + tv := mustReadFile(t, "testdata/collection-cbor-mixed-keys.cbor") + + var actual Collection + err := actual.UnmarshalCBOR(tv) + assert.NoError(t, err) + + for k := range actual.GetMap() { + switch v := k.(type) { + case string: + assert.Equal(t, "string", v) + case uint64: + assert.Equal(t, uint64(1024), v) + default: + t.FailNow() + } + } +} + +func Test_Collection_detectSerialization_fail(t *testing.T) { + var tv Collection + + var a CMW + a.SetMediaType("application/vnd.a") + a.SetValue([]byte{0x61}) + a.SetSerialization(JSONArray) + + tv.AddItem("a", a) + + var b CMW + b.SetMediaType("application/vnd.b") + b.SetValue([]byte{0x62}) + b.SetSerialization(CBORArray) + + tv.AddItem("b", b) + + s, err := tv.detectSerialization() + assert.EqualError(t, err, "CMW collection has items with incompatible serializations") + assert.Equal(t, UnknownCollectionSerialization, s) +} + +func Test_Collection_Deserialize_JSON_ok(t *testing.T) { + tv := mustReadFile(t, "testdata/collection-ok.json") + + var c Collection + err := c.Deserialize(tv) + assert.NoError(t, err) +} + +func Test_Collection_Deserialize_CBOR_ok(t *testing.T) { + tv := mustReadFile(t, "testdata/collection-cbor-ok.cbor") + + var c Collection + err := c.Deserialize(tv) + assert.NoError(t, err) +} diff --git a/testdata/Makefile b/testdata/Makefile new file mode 100644 index 0000000..b538de0 --- /dev/null +++ b/testdata/Makefile @@ -0,0 +1,13 @@ +# Copyright 2023 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +DIAG_TESTDATA := $(wildcard *.diag) +CBOR_TESTDATA := $(DIAG_TESTDATA:.diag=.cbor) + +%.cbor: %.diag ; diag2cbor.rb $< > $@ + +CLEANFILES += $(CBOR_TESTDATA) + +all: $(CBOR_TESTDATA) + +clean: ; $(RM) -f $(CLEANFILES) diff --git a/testdata/collection-cbor-mixed-keys.cbor b/testdata/collection-cbor-mixed-keys.cbor new file mode 100644 index 0000000..08be7b6 Binary files /dev/null and b/testdata/collection-cbor-mixed-keys.cbor differ diff --git a/testdata/collection-cbor-mixed-keys.diag b/testdata/collection-cbor-mixed-keys.diag new file mode 100644 index 0000000..5449d8a --- /dev/null +++ b/testdata/collection-cbor-mixed-keys.diag @@ -0,0 +1,7 @@ +{ + "string": [ + 0, + h'ff' + ], + 1024: 10000(h'aa') +} diff --git a/testdata/collection-cbor-ok-2.cbor b/testdata/collection-cbor-ok-2.cbor new file mode 100644 index 0000000..3d126a7 --- /dev/null +++ b/testdata/collection-cbor-ok-2.cbor @@ -0,0 +1 @@ +¡‚qapplication/vnd.1DÞ­¾ï \ No newline at end of file diff --git a/testdata/collection-cbor-ok-2.diag b/testdata/collection-cbor-ok-2.diag new file mode 100644 index 0000000..ed07d1c --- /dev/null +++ b/testdata/collection-cbor-ok-2.diag @@ -0,0 +1,6 @@ +{ + 1: [ + "application/vnd.1", + h'DEADBEEF' + ] +} diff --git a/testdata/collection-cbor-ok.cbor b/testdata/collection-cbor-ok.cbor new file mode 100644 index 0000000..6d30cad --- /dev/null +++ b/testdata/collection-cbor-ok.cbor @@ -0,0 +1 @@ +£ƒxapplication/signed-corim+cborGÒ„C¡&¡Úctv2D#GÚUas‚u1D#GÚU \ No newline at end of file diff --git a/testdata/collection-cbor-ok.diag b/testdata/collection-cbor-ok.diag new file mode 100644 index 0000000..d9d3faf --- /dev/null +++ b/testdata/collection-cbor-ok.diag @@ -0,0 +1,12 @@ +{ + 1: [ + "application/signed-corim+cbor", + h'd28443a10126a1', + 3 + ], + 2: 1668576818(h'2347da55'), + "s": [ + 30001, + h'2347da55' + ] +} diff --git a/testdata/collection-ok.json b/testdata/collection-ok.json new file mode 100644 index 0000000..d76c15c --- /dev/null +++ b/testdata/collection-ok.json @@ -0,0 +1,10 @@ +{ + "a": [ + "application/vnd.a", + "YQ" + ], + "b": [ + "application/vnd.b", + "Yg" + ] +} diff --git a/type.go b/type.go index 4610742..84083fe 100644 --- a/type.go +++ b/type.go @@ -47,8 +47,8 @@ func (o *Type) UnmarshalJSON(b []byte) error { return typeDecode(json.Unmarshal, func (o *Type) UnmarshalCBOR(b []byte) error { return typeDecode(cbor.Unmarshal, b, o) } type ( - typeDecoder func([]byte, interface{}) error - typeEncoder func(interface{}) ([]byte, error) + typeDecoder func([]byte, any) error + typeEncoder func(any) ([]byte, error) ) func typeDecode(dec typeDecoder, b []byte, o *Type) error {