Skip to content

Commit

Permalink
feat(delegation): update to provide encoding/decoding straight from/t…
Browse files Browse the repository at this point in the history
…o View
  • Loading branch information
smoyer64 committed Sep 18, 2024
1 parent baf3edc commit f44b5cb
Show file tree
Hide file tree
Showing 8 changed files with 379 additions and 74 deletions.
1 change: 1 addition & 0 deletions delegation/delegation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package delegation
142 changes: 142 additions & 0 deletions delegation/delegation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package delegation_test

import (
"crypto/rand"
"testing"

"github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/require"
"github.com/ucan-wg/go-ucan/did"
)

const (
nonce = "6roDhGi0kiNriQAz7J3d+bOeoI/tj8ENikmQNbtjnD0"

AudiencePrivKeyCfg = "CAESQL1hvbXpiuk2pWr/XFbfHJcZNpJ7S90iTA3wSCTc/BPRneCwPnCZb6c0vlD6ytDWqaOt0HEOPYnqEpnzoBDprSM="
AudienceDID = "did:key:z6Mkq5YmbJcTrPExNDi26imrTCpKhepjBFBSHqrBDN2ArPkv"

issuerPrivKeyCfg = "CAESQLSql38oDmQXIihFFaYIjb73mwbPsc7MIqn4o8PN4kRNnKfHkw5gRP1IV9b6d0estqkZayGZ2vqMAbhRixjgkDU="
issuerDID = "did:key:z6Mkpzn2n3ZGT2VaqMGSQC3tzmzV4TS9S71iFsDXE1WnoNH2"

subjectPrivKeyCfg = "CAESQL9RtjZ4dQBeXtvDe53UyvslSd64kSGevjdNiA1IP+hey5i/3PfRXSuDr71UeJUo1fLzZ7mGldZCOZL3gsIQz5c="
subjectDID = "did:key:z6MktA1uBdCpq4uJBqE9jjMiLyxZBg9a6xgPPKJjMqss6Zc2"
subJectCmd = "/foo/bar"
subjectPol = `
[
[
"==",
".status",
"draft"
],
[
"all",
".reviewer",
[
"like",
".email",
"*@example.com"
]
],
[
"any",
".tags",
[
"or",
[
[
"==",
".",
"news"
],
[
"==",
".",
"press"
]
]
]
]
]
`
)

// func TestConstructors(t *testing.T) {
// t.Parallel()

// privKey := privKey(t, issuerPrivKeyCfg)

// aud, err := did.Parse(AudienceDID)

// sub, err := did.Parse(subjectDID)
// require.NoError(t, err)

// cmd, err := command.Parse(subJectCmd)
// require.NoError(t, err)

// pol, err := policy.FromDagJson(subjectPol)
// require.NoError(t, err)

// exp := time.Time{}

// 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, &sub, cmd, pol, []byte(nonce), delegation.WithExpiration(&exp), delegation.WithMeta(meta))
// require.NoError(t, err)

// data, err := dlg.ToDagJson()
// require.NoError(t, err)

// t.Log(string(data))

// golden.Assert(t, string(data), "new.dagjson")
// })

// t.Run("Root", func(t *testing.T) {
// t.Parallel()

// dlg, err := delegation.Root(privKey, aud, cmd, pol, []byte(nonce), delegation.WithExpiration(&exp), delegation.WithMeta(meta))
// require.NoError(t, err)

// data, err := dlg.ToDagJson()
// require.NoError(t, err)

// t.Log(string(data))

// golden.Assert(t, string(data), "root.dagjson")
// })
// }

func privKey(t *testing.T, privKeyCfg string) crypto.PrivKey {
t.Helper()

privKeyMar, err := crypto.ConfigDecodeKey(privKeyCfg)
require.NoError(t, err)

privKey, err := crypto.UnmarshalPrivateKey(privKeyMar)
require.NoError(t, err)

return privKey
}

func TestKey(t *testing.T) {
t.Skip()

priv, _, err := crypto.GenerateEd25519Key(rand.Reader)
require.NoError(t, err)

privMar, err := crypto.MarshalPrivateKey(priv)
require.NoError(t, err)

privCfg := crypto.ConfigEncodeKey(privMar)
t.Log(privCfg)

id, err := did.FromPubKey(priv.GetPublic())
require.NoError(t, err)
t.Log(id)

t.Fail()
}
33 changes: 0 additions & 33 deletions delegation/encoding.go

This file was deleted.

168 changes: 168 additions & 0 deletions delegation/ipld.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package delegation

import (
"io"

"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec"
"github.com/ipld/go-ipld-prime/codec/dagcbor"
"github.com/ipld/go-ipld-prime/codec/dagjson"
"github.com/ipld/go-ipld-prime/datamodel"
"github.com/libp2p/go-libp2p/core/crypto"

"github.com/ucan-wg/go-ucan/did"
"github.com/ucan-wg/go-ucan/internal/envelope"
)

// Encode marshals a View to the format specified by the provided
// codec.Encoder.
func (d *View) Encode(privKey crypto.PrivKey, encFn codec.Encoder) ([]byte, error) {
node, err := d.ToIPLD(privKey)
if err != nil {
return nil, err
}

return ipld.Encode(node, encFn)
}

// EncodeWriter is the same as Encode but accepts an io.Writer.
func (d *View) EncodeWriter(w io.Writer, privKey crypto.PrivKey, encFn codec.Encoder) error {
node, err := d.ToIPLD(privKey)
if err != nil {
return err
}

return ipld.EncodeStreaming(w, node, encFn)
}

// ToDagCbor marshals the View to the DAG-CBOR format.
func (d *View) ToDagCbor(privKey crypto.PrivKey) ([]byte, error) {
return d.Encode(privKey, dagcbor.Encode)
}

// ToDagCborWriter is the same as ToDagCbor but it accepts an io.Writer.
func (d *View) ToDagCborWriter(w io.Writer, privKey crypto.PrivKey) error {
return d.EncodeWriter(w, privKey, dagcbor.Encode)
}

// ToDagJson marshals the View to the DAG-JSON format.
func (d *View) ToDagJson(privKey crypto.PrivKey) ([]byte, error) {
return d.Encode(privKey, dagjson.Encode)
}

// ToDagJsonWriter is the same as ToDagJson but it accepts an io.Writer.
func (d *View) ToDagJsonWriter(w io.Writer, privKey crypto.PrivKey) error {
return d.EncodeWriter(w, privKey, dagjson.Encode)
}

// ToIPLD wraps the View in an IPLD datamodel.Node.
func (d *View) ToIPLD(privKey crypto.PrivKey) (datamodel.Node, error) {
var sub *string
if d.Subject != did.Undef {
s := d.Subject.String()
sub = &s
}

pol, err := d.Policy.ToIPLD()
if err != nil {
return nil, err
}

metaKeys := make([]string, len(d.Meta))
i := 0

for k := range d.Meta {
metaKeys[i] = k
i++
}

var nbf *int64
if d.NotBefore != nil {
u := d.NotBefore.Unix()
nbf = &u
}

var exp *int64
if d.Expiration != nil {
u := d.Expiration.Unix()
exp = &u
}

model := &PayloadModel{
Iss: d.Issuer.String(),
Aud: d.Audience.String(),
Sub: sub,
Cmd: d.Command.String(),
Pol: pol,
Nonce: d.Nonce,
Meta: MetaModel{
Keys: metaKeys,
Values: d.Meta,
},
Nbf: nbf,
Exp: exp,
}

return envelope.ToIPLD(privKey, model)
}

// Decode unmarshals the input data using the format specified by the
// provided codec.Decoder into a View.
//
// An error is returned if the conversion fails, or if the resulting
// View is invalid.
func Decode(b []byte, decFn codec.Decoder) (*View, error) {
node, err := ipld.Decode(b, decFn)
if err != nil {
return nil, err
}
return FromIPLD(node)
}

// DecodeReader is the same as Decode, but accept an io.Reader.
func DecodeReader(r io.Reader, decFn codec.Decoder) (*View, error) {
node, err := ipld.DecodeStreaming(r, decFn)
if err != nil {
return nil, err
}
return FromIPLD(node)
}

// FromDagCbor unmarshals the input data into a View.
//
// An error is returned if the conversion fails, or if the resulting
// View is invalid.
func FromDagCbor(data []byte) (*View, error) {
return Decode(data, dagcbor.Decode)
}

// FromDagCborReader is the same as FromDagCbor, but accept an io.Reader.
func FromDagCborReader(r io.Reader) (*View, error) {
return DecodeReader(r, dagcbor.Decode)
}

// FromDagJson unmarshals the input data into a View.
//
// An error is returned if the conversion fails, or if the resulting
// View is invalid.
func FromDagJson(data []byte) (*View, error) {
return Decode(data, dagjson.Decode)
}

// FromDagJsonReader is the same as FromDagJson, but accept an io.Reader.
func FromDagJsonReader(r io.Reader) (*View, error) {
return DecodeReader(r, dagjson.Decode)
}

// FromIPLD unwraps a View from the provided IPLD datamodel.Node
//
// An error is returned if the conversion fails, or if the resulting
// View is invalid.
func FromIPLD(node datamodel.Node) (*View, error) {
tkn, _, err := envelope.FromIPLD[*PayloadModel](node) // TODO add CID to view
if err != nil {
return nil, err
}

return ViewFromModel(*tkn)
}
14 changes: 14 additions & 0 deletions delegation/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import (

"github.com/ipld/go-ipld-prime"
"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"
)

const Tag = "ucan/[email protected]"

//go:embed delegation.ipldsch
var schemaBytes []byte

Expand All @@ -33,6 +37,8 @@ func PayloadType() schema.Type {
return mustLoadSchema().TypeByName("Payload")
}

var _ envelope.Tokener = (*PayloadModel)(nil)

type PayloadModel struct {
// Issuer DID (sender)
Iss string
Expand Down Expand Up @@ -63,6 +69,14 @@ type PayloadModel struct {
Exp *int64
}

func (e *PayloadModel) Prototype() schema.TypedPrototype {
return bindnode.Prototype((*PayloadModel)(nil), PayloadType())
}

func (*PayloadModel) Tag() string {
return Tag
}

type MetaModel struct {
Keys []string
Values map[string]datamodel.Node
Expand Down
Loading

0 comments on commit f44b5cb

Please sign in to comment.