Merge pull request #61 from ucan-wg/v1-token-container-versioning
feat(container): versioning
This commit is contained in:
@@ -40,6 +40,13 @@ func TestCarRoundTrip(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FuzzCarRoundTrip(f *testing.F) {
|
func FuzzCarRoundTrip(f *testing.F) {
|
||||||
|
// Note: this fuzzing is somewhat broken.
|
||||||
|
// After some time, the fuzzer discover that a varint can be serialized in different
|
||||||
|
// ways that lead to the same integer value. This means that the CAR format can have
|
||||||
|
// multiple legal binary representation for the exact same data, which is what we are
|
||||||
|
// trying to detect here. Ideally, the format would be stricter, but that's how things
|
||||||
|
// are.
|
||||||
|
|
||||||
example, err := os.ReadFile("testdata/sample-v1.car")
|
example, err := os.ReadFile("testdata/sample-v1.car")
|
||||||
require.NoError(f, err)
|
require.NoError(f, err)
|
||||||
|
|
||||||
|
|||||||
@@ -98,15 +98,36 @@ func FromCbor(r io.Reader) (Reader, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if n.Kind() != datamodel.Kind_List {
|
if n.Kind() != datamodel.Kind_Map {
|
||||||
return nil, fmt.Errorf("not a list")
|
return nil, fmt.Errorf("invalid container format: expected map")
|
||||||
|
}
|
||||||
|
if n.Length() != 1 {
|
||||||
|
return nil, fmt.Errorf("invalid container format: expected single version key")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctn := make(Reader, n.Length())
|
// get the first (and only) key-value pair
|
||||||
|
it := n.MapIterator()
|
||||||
|
key, tokensNode, err := it.Next()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
it := n.ListIterator()
|
version, err := key.AsString()
|
||||||
for !it.Done() {
|
if err != nil {
|
||||||
_, val, err := it.Next()
|
return nil, fmt.Errorf("invalid container format: version must be string")
|
||||||
|
}
|
||||||
|
if version != currentContainerVersion {
|
||||||
|
return nil, fmt.Errorf("unsupported container version: %s", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tokensNode.Kind() != datamodel.Kind_List {
|
||||||
|
return nil, fmt.Errorf("invalid container format: tokens must be a list")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctn := make(Reader, tokensNode.Length())
|
||||||
|
it2 := tokensNode.ListIterator()
|
||||||
|
for !it2.Done() {
|
||||||
|
_, val, err := it2.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,3 +176,30 @@ func randToken() (*delegation.Token, cid.Cid, []byte) {
|
|||||||
}
|
}
|
||||||
return t, c, b
|
return t, c, b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FuzzContainerRead(f *testing.F) {
|
||||||
|
// Generate a corpus
|
||||||
|
for tokenCount := 0; tokenCount < 10; tokenCount++ {
|
||||||
|
writer := NewWriter()
|
||||||
|
for i := 0; i < tokenCount; i++ {
|
||||||
|
_, c, data := randToken()
|
||||||
|
writer.AddSealed(c, data)
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := writer.ToCbor(buf)
|
||||||
|
require.NoError(f, err)
|
||||||
|
|
||||||
|
f.Add(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Fuzz(func(t *testing.T, data []byte) {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
// search for panics
|
||||||
|
_, _ = FromCbor(bytes.NewReader(data))
|
||||||
|
|
||||||
|
if time.Since(start) > 100*time.Millisecond {
|
||||||
|
panic("too long")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import (
|
|||||||
|
|
||||||
// TODO: should we have a multibase to wrap the cbor? but there is no reader/write in go-multibase :-(
|
// TODO: should we have a multibase to wrap the cbor? but there is no reader/write in go-multibase :-(
|
||||||
|
|
||||||
|
const currentContainerVersion = "ctn-v1"
|
||||||
|
|
||||||
// Writer is a token container writer. It provides a convenient way to aggregate and serialize tokens together.
|
// Writer is a token container writer. It provides a convenient way to aggregate and serialize tokens together.
|
||||||
type Writer map[cid.Cid][]byte
|
type Writer map[cid.Cid][]byte
|
||||||
|
|
||||||
@@ -43,10 +45,12 @@ func (ctn Writer) ToCarBase64(w io.Writer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctn Writer) ToCbor(w io.Writer) error {
|
func (ctn Writer) ToCbor(w io.Writer) error {
|
||||||
node, err := qp.BuildList(basicnode.Prototype.Any, int64(len(ctn)), func(la datamodel.ListAssembler) {
|
node, err := qp.BuildMap(basicnode.Prototype.Any, 1, func(ma datamodel.MapAssembler) {
|
||||||
for _, bytes := range ctn {
|
qp.MapEntry(ma, currentContainerVersion, qp.List(int64(len(ctn)), func(la datamodel.ListAssembler) {
|
||||||
qp.ListEntry(la, qp.Bytes(bytes))
|
for _, bytes := range ctn {
|
||||||
}
|
qp.ListEntry(la, qp.Bytes(bytes))
|
||||||
|
}
|
||||||
|
}))
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in New Issue
Block a user