diff --git a/delegation/delegation.go b/delegation/delegation.go index 037d270..c06e7c2 100644 --- a/delegation/delegation.go +++ b/delegation/delegation.go @@ -5,12 +5,12 @@ import ( "fmt" "time" - "github.com/ipld/go-ipld-prime/datamodel" "github.com/libp2p/go-libp2p/core/crypto" "github.com/ucan-wg/go-ucan/capability/command" "github.com/ucan-wg/go-ucan/capability/policy" "github.com/ucan-wg/go-ucan/did" + "github.com/ucan-wg/go-ucan/pkg/meta" ) type Token struct { @@ -27,7 +27,7 @@ type Token struct { // A unique, random nonce nonce []byte // Arbitrary Metadata - meta map[string]datamodel.Node + meta *meta.Meta // "Not before" UTC Unix Timestamp in seconds (valid from), 53-bits integer notBefore *time.Time // The timestamp at which the Invocation becomes invalid @@ -47,6 +47,7 @@ func New(privKey crypto.PrivKey, aud did.DID, cmd *command.Command, pol policy.P subject: did.Undef, command: cmd, policy: pol, + meta: meta.NewMeta(), nonce: nonce, } @@ -109,7 +110,7 @@ func (t *Token) Nonce() []byte { } // Meta returns the Token's metadata. -func (t *Token) Meta() map[string]datamodel.Node { +func (t *Token) Meta() *meta.Meta { return t.meta } @@ -165,13 +166,13 @@ func WithExpiration(exp time.Time) Option { } } -// WithMetadata sets the Token's optional "meta" field to the provided -// value. -func WithMetadata(meta map[string]datamodel.Node) Option { +// WithMeta adds a key/value pair in the "meta" field. +// WithMeta can be used multiple times in the same call. +// Accepted types for the value are: bool, string, int, int32, int64, []byte, +// and ipld.Node. +func WithMeta(key string, val any) Option { return func(t *Token) error { - t.meta = meta - - return nil + return t.meta.Add(key, val) } } @@ -246,8 +247,7 @@ func tokenFromModel(m tokenPayloadModel) (*Token, error) { } tkn.nonce = m.Nonce - // TODO: copy? - tkn.meta = m.Meta.Values + tkn.meta = &m.Meta if m.Nbf != nil { t := time.Unix(*m.Nbf, 0) diff --git a/delegation/delegation_test.go b/delegation/delegation_test.go index 55934de..62feeae 100644 --- a/delegation/delegation_test.go +++ b/delegation/delegation_test.go @@ -5,15 +5,14 @@ import ( "testing" "time" - "github.com/ipld/go-ipld-prime/datamodel" - "github.com/ipld/go-ipld-prime/node/basicnode" "github.com/libp2p/go-libp2p/core/crypto" "github.com/stretchr/testify/require" + "gotest.tools/v3/golden" + "github.com/ucan-wg/go-ucan/capability/command" "github.com/ucan-wg/go-ucan/capability/policy" "github.com/ucan-wg/go-ucan/delegation" "github.com/ucan-wg/go-ucan/did" - "gotest.tools/v3/golden" ) const ( @@ -86,13 +85,13 @@ func TestConstructors(t *testing.T) { exp, err := time.Parse(time.RFC3339, "2200-01-01T00:00:00Z") require.NoError(t, err) - meta := map[string]datamodel.Node{ - "foo": basicnode.NewString("fooo"), - "bar": basicnode.NewString("barr"), - } - t.Run("New", func(t *testing.T) { - dlg, err := delegation.New(privKey, aud, cmd, pol, []byte(nonce), delegation.WithSubject(sub), delegation.WithExpiration(exp), delegation.WithMetadata(meta)) + dlg, err := delegation.New(privKey, aud, cmd, pol, []byte(nonce), + delegation.WithSubject(sub), + delegation.WithExpiration(exp), + delegation.WithMeta("foo", "fooo"), + delegation.WithMeta("bar", "barr"), + ) require.NoError(t, err) data, err := dlg.ToDagJson(privKey) @@ -106,7 +105,11 @@ func TestConstructors(t *testing.T) { t.Run("Root", func(t *testing.T) { t.Parallel() - dlg, err := delegation.Root(privKey, aud, cmd, pol, []byte(nonce), delegation.WithExpiration(exp), delegation.WithMetadata(meta)) + dlg, err := delegation.Root(privKey, aud, cmd, pol, []byte(nonce), + delegation.WithExpiration(exp), + delegation.WithMeta("foo", "fooo"), + delegation.WithMeta("bar", "barr"), + ) require.NoError(t, err) data, err := dlg.ToDagJson(privKey) diff --git a/delegation/ipld.go b/delegation/ipld.go index c3d16e0..a900238 100644 --- a/delegation/ipld.go +++ b/delegation/ipld.go @@ -68,14 +68,6 @@ func (t *Token) ToIPLD(privKey crypto.PrivKey) (datamodel.Node, error) { return nil, err } - metaKeys := make([]string, len(t.meta)) - i := 0 - - for k := range t.meta { - metaKeys[i] = k - i++ - } - var nbf *int64 if t.notBefore != nil { u := t.notBefore.Unix() @@ -95,12 +87,9 @@ func (t *Token) ToIPLD(privKey crypto.PrivKey) (datamodel.Node, error) { Cmd: t.command.String(), Pol: pol, Nonce: t.nonce, - Meta: metaModel{ - Keys: metaKeys, - Values: t.meta, - }, - Nbf: nbf, - Exp: exp, + Meta: *t.meta, + Nbf: nbf, + Exp: exp, } return envelope.ToIPLD(privKey, model) diff --git a/delegation/schema.go b/delegation/schema.go index d4e9f57..33b8f46 100644 --- a/delegation/schema.go +++ b/delegation/schema.go @@ -9,7 +9,9 @@ import ( "github.com/ipld/go-ipld-prime/datamodel" "github.com/ipld/go-ipld-prime/node/bindnode" "github.com/ipld/go-ipld-prime/schema" + "github.com/ucan-wg/go-ucan/internal/envelope" + "github.com/ucan-wg/go-ucan/pkg/meta" ) const Tag = "ucan/dlg@1.0.0-rc.1" @@ -58,8 +60,7 @@ type tokenPayloadModel struct { Nonce []byte // Arbitrary Metadata - // optional: can be nil - Meta metaModel + Meta meta.Meta // "Not before" UTC Unix Timestamp in seconds (valid from), 53-bits integer // optional: can be nil @@ -76,8 +77,3 @@ func (e *tokenPayloadModel) Prototype() schema.TypedPrototype { func (*tokenPayloadModel) Tag() string { return Tag } - -type metaModel struct { - Keys []string - Values map[string]datamodel.Node -} diff --git a/delegation/schema_test.go b/delegation/schema_test.go index 75a839d..0f534df 100644 --- a/delegation/schema_test.go +++ b/delegation/schema_test.go @@ -7,8 +7,9 @@ import ( "github.com/ipld/go-ipld-prime" "github.com/stretchr/testify/require" - "github.com/ucan-wg/go-ucan/delegation" "gotest.tools/v3/golden" + + "github.com/ucan-wg/go-ucan/delegation" ) //go:embed delegation.ipldsch diff --git a/pkg/meta/meta.go b/pkg/meta/meta.go index 40f604c..176c5fe 100644 --- a/pkg/meta/meta.go +++ b/pkg/meta/meta.go @@ -26,7 +26,7 @@ func NewMeta() *Meta { // GetBool retrieves a value as a bool. // Returns ErrNotFound if the given key is missing. // Returns datamodel.ErrWrongKind if the value has the wrong type. -func (m Meta) GetBool(key string) (bool, error) { +func (m *Meta) GetBool(key string) (bool, error) { v, ok := m.Values[key] if !ok { return false, ErrNotFound @@ -37,7 +37,7 @@ func (m Meta) GetBool(key string) (bool, error) { // GetString retrieves a value as a string. // Returns ErrNotFound if the given key is missing. // Returns datamodel.ErrWrongKind if the value has the wrong type. -func (m Meta) GetString(key string) (string, error) { +func (m *Meta) GetString(key string) (string, error) { v, ok := m.Values[key] if !ok { return "", ErrNotFound @@ -48,7 +48,7 @@ func (m Meta) GetString(key string) (string, error) { // GetInt64 retrieves a value as an int64. // Returns ErrNotFound if the given key is missing. // Returns datamodel.ErrWrongKind if the value has the wrong type. -func (m Meta) GetInt64(key string) (int64, error) { +func (m *Meta) GetInt64(key string) (int64, error) { v, ok := m.Values[key] if !ok { return 0, ErrNotFound @@ -59,7 +59,7 @@ func (m Meta) GetInt64(key string) (int64, error) { // GetFloat64 retrieves a value as a float64. // Returns ErrNotFound if the given key is missing. // Returns datamodel.ErrWrongKind if the value has the wrong type. -func (m Meta) GetFloat64(key string) (float64, error) { +func (m *Meta) GetFloat64(key string) (float64, error) { v, ok := m.Values[key] if !ok { return 0, ErrNotFound @@ -70,7 +70,7 @@ func (m Meta) GetFloat64(key string) (float64, error) { // GetBytes retrieves a value as a []byte. // Returns ErrNotFound if the given key is missing. // Returns datamodel.ErrWrongKind if the value has the wrong type. -func (m Meta) GetBytes(key string) ([]byte, error) { +func (m *Meta) GetBytes(key string) ([]byte, error) { v, ok := m.Values[key] if !ok { return nil, ErrNotFound @@ -81,7 +81,7 @@ func (m Meta) GetBytes(key string) ([]byte, error) { // GetNode retrieves a value as a raw IPLD node. // Returns ErrNotFound if the given key is missing. // Returns datamodel.ErrWrongKind if the value has the wrong type. -func (m Meta) GetNode(key string) (ipld.Node, error) { +func (m *Meta) GetNode(key string) (ipld.Node, error) { v, ok := m.Values[key] if !ok { return nil, ErrNotFound @@ -92,7 +92,7 @@ func (m Meta) GetNode(key string) (ipld.Node, error) { // Add adds a key/value pair in the meta set. // Accepted types for the value are: bool, string, int, int32, int64, []byte, // and ipld.Node. -func (m Meta) Add(key string, val any) error { +func (m *Meta) Add(key string, val any) error { switch val := val.(type) { case bool: m.Values[key] = basicnode.NewBool(val)