Skip to content

Commit

Permalink
fix: correct json codec links & bytes handling
Browse files Browse the repository at this point in the history
The plain JSON codec shouldn't be able to encode bytes or links and should
consistently error. The DAG-JSON codec should be able to, of course.
  • Loading branch information
rvagg committed Oct 13, 2022
1 parent 7548eb8 commit 146d1c8
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 42 deletions.
76 changes: 36 additions & 40 deletions codec/dagjson/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,54 +202,50 @@ func Marshal(n datamodel.Node, sink shared.TokenSink, options EncodeOptions) err
_, err = sink.Step(&tk)
return err
case datamodel.Kind_Bytes:
if !options.EncodeBytes {
return fmt.Errorf("cannot marshal IPLD bytes to this codec")
}
v, err := n.AsBytes()
if err != nil {
return err
}
if options.EncodeBytes {
// Precisely seven tokens to emit:
tk.Type = tok.TMapOpen
tk.Length = 1
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Type = tok.TString
tk.Str = "/"
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Type = tok.TMapOpen
tk.Length = 1
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Type = tok.TString
tk.Str = "bytes"
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Str = base64.RawStdEncoding.EncodeToString(v)
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Type = tok.TMapClose
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Type = tok.TMapClose
if _, err = sink.Step(&tk); err != nil {
return err
}
return nil
} else {
tk.Type = tok.TBytes
tk.Bytes = v
_, err = sink.Step(&tk)
// Precisely seven tokens to emit:
tk.Type = tok.TMapOpen
tk.Length = 1
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Type = tok.TString
tk.Str = "/"
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Type = tok.TMapOpen
tk.Length = 1
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Type = tok.TString
tk.Str = "bytes"
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Str = base64.RawStdEncoding.EncodeToString(v)
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Type = tok.TMapClose
if _, err = sink.Step(&tk); err != nil {
return err
}
tk.Type = tok.TMapClose
if _, err = sink.Step(&tk); err != nil {
return err
}
return nil
case datamodel.Kind_Link:
if !options.EncodeLinks {
return fmt.Errorf("cannot Marshal ipld links to JSON")
return fmt.Errorf("cannot marshal IPLD links to this codec")
}
v, err := n.AsLink()
if err != nil {
Expand Down
48 changes: 46 additions & 2 deletions codec/dagjson/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
"github.com/ipld/go-ipld-prime/node/basicnode"
)

var link = cid.MustParse("bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi")

func TestMarshalUndefCid(t *testing.T) {
link, err := cid.Decode("bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi")
qt.Assert(t, err, qt.IsNil)
node, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {
qp.MapEntry(ma, "UndefCid", qp.Link(cidlink.Link{Cid: cid.Undef}))
qp.MapEntry(ma, "DefCid", qp.Link(cidlink.Link{Cid: link}))
Expand All @@ -23,3 +23,47 @@ func TestMarshalUndefCid(t *testing.T) {
_, err = ipld.Encode(node, Encode)
qt.Assert(t, err, qt.ErrorMatches, "encoding undefined CIDs are not supported by this codec")
}

// mirrored in json but with errors
func TestMarshalLinks(t *testing.T) {
linkNode := basicnode.NewLink(cidlink.Link{Cid: link})
mapNode, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {
qp.MapEntry(ma, "Lnk", qp.Node(linkNode))
})
qt.Assert(t, err, qt.IsNil)

t.Run("link dag-json", func(t *testing.T) {
byts, err := ipld.Encode(linkNode, Encode)
qt.Assert(t, err, qt.IsNil)
qt.Assert(t, string(byts), qt.Equals,
`{"/":"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"}`)
})
t.Run("nested link dag-json", func(t *testing.T) {
byts, err := ipld.Encode(mapNode, Encode)
qt.Assert(t, err, qt.IsNil)
qt.Assert(t, string(byts), qt.Equals,
`{"Lnk":{"/":"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"}}`)
})
}

// mirrored in json but with errors
func TestMarshalBytes(t *testing.T) {
bytsNode := basicnode.NewBytes([]byte("byte me"))
mapNode, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {
qp.MapEntry(ma, "Byts", qp.Node(bytsNode))
})
qt.Assert(t, err, qt.IsNil)

t.Run("bytes dag-json", func(t *testing.T) {
byts, err := ipld.Encode(bytsNode, Encode)
qt.Assert(t, err, qt.IsNil)
qt.Assert(t, string(byts), qt.Equals,
`{"/":{"bytes":"Ynl0ZSBtZQ"}}`)
})
t.Run("nested bytes dag-json", func(t *testing.T) {
byts, err := ipld.Encode(mapNode, Encode)
qt.Assert(t, err, qt.IsNil)
qt.Assert(t, string(byts), qt.Equals,
`{"Byts":{"/":{"bytes":"Ynl0ZSBtZQ"}}}`)
})
}
51 changes: 51 additions & 0 deletions codec/json/marshal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package json

import (
"testing"

qt "github.com/frankban/quicktest"
"github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/datamodel"
"github.com/ipld/go-ipld-prime/fluent/qp"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"github.com/ipld/go-ipld-prime/node/basicnode"
)

var link = cid.MustParse("bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi")

// mirrored in dag-json but without errors
func TestMarshalLinks(t *testing.T) {
linkNode := basicnode.NewLink(cidlink.Link{Cid: link})
mapNode, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {
qp.MapEntry(ma, "Lnk", qp.Node(linkNode))
})
qt.Assert(t, err, qt.IsNil)

t.Run("link json", func(t *testing.T) {
_, err := ipld.Encode(linkNode, Encode)
qt.Assert(t, err, qt.ErrorMatches, "cannot marshal IPLD links to this codec")
})
t.Run("nested link json", func(t *testing.T) {
_, err := ipld.Encode(mapNode, Encode)
qt.Assert(t, err, qt.ErrorMatches, "cannot marshal IPLD links to this codec")
})
}

// mirrored in dag-json but without errors
func TestMarshalBytes(t *testing.T) {
bytsNode := basicnode.NewBytes([]byte("byte me"))
mapNode, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {
qp.MapEntry(ma, "Byts", qp.Node(bytsNode))
})
qt.Assert(t, err, qt.IsNil)

t.Run("bytes json", func(t *testing.T) {
_, err := ipld.Encode(bytsNode, Encode)
qt.Assert(t, err, qt.ErrorMatches, "cannot marshal IPLD bytes to this codec")
})
t.Run("nested bytes json", func(t *testing.T) {
_, err := ipld.Encode(mapNode, Encode)
qt.Assert(t, err, qt.ErrorMatches, "cannot marshal IPLD bytes to this codec")
})
}

0 comments on commit 146d1c8

Please sign in to comment.