delegation: first import with rough IPLD round-trip
This commit is contained in:
32
delegation/delegation.ipldsch
Normal file
32
delegation/delegation.ipldsch
Normal file
@@ -0,0 +1,32 @@
|
||||
type DID string
|
||||
|
||||
# The Delegation payload MUST describe the authorization claims, who is involved, and its validity period.
|
||||
type Payload struct {
|
||||
# Issuer DID (sender)
|
||||
iss DID
|
||||
# Audience DID (receiver)
|
||||
aud DID
|
||||
# Principal that the chain is about (the Subject)
|
||||
sub optional DID
|
||||
|
||||
# The Command to eventually invoke
|
||||
cmd String
|
||||
|
||||
# The delegation policy
|
||||
pol Policy
|
||||
|
||||
# A unique, random nonce
|
||||
nonce Bytes
|
||||
|
||||
# Arbitrary Metadata
|
||||
meta {String : Any}
|
||||
|
||||
# "Not before" UTC Unix Timestamp in seconds (valid from), 53-bits integer
|
||||
nbf optional Int
|
||||
# The timestamp at which the Invocation becomes invalid
|
||||
exp nullable Int
|
||||
}
|
||||
|
||||
type Policy struct {
|
||||
|
||||
}
|
||||
33
delegation/encoding.go
Normal file
33
delegation/encoding.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package delegation
|
||||
|
||||
import (
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
"github.com/ipld/go-ipld-prime/codec/dagcbor"
|
||||
"github.com/ipld/go-ipld-prime/codec/dagjson"
|
||||
)
|
||||
|
||||
func (p *PayloadModel) EncodeDagCbor() ([]byte, error) {
|
||||
return ipld.Marshal(dagcbor.Encode, p, PayloadType())
|
||||
}
|
||||
|
||||
func (p *PayloadModel) EncodeDagJson() ([]byte, error) {
|
||||
return ipld.Marshal(dagjson.Encode, p, PayloadType())
|
||||
}
|
||||
|
||||
func DecodeDagCbor(data []byte) (*PayloadModel, error) {
|
||||
var p PayloadModel
|
||||
_, err := ipld.Unmarshal(data, dagcbor.Decode, &p, PayloadType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func DecodeDagJson(data []byte) (*PayloadModel, error) {
|
||||
var p PayloadModel
|
||||
_, err := ipld.Unmarshal(data, dagjson.Decode, &p, PayloadType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
"github.com/ipld/go-ipld-prime/must"
|
||||
"github.com/storacha-network/go-ucanto/core/policy/selector"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/delegation/policy/selector"
|
||||
)
|
||||
|
||||
// Match determines if the IPLD node matches the policy document.
|
||||
|
||||
@@ -9,9 +9,10 @@ import (
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
|
||||
"github.com/ipld/go-ipld-prime/node/basicnode"
|
||||
"github.com/storacha-network/go-ucanto/core/policy/literal"
|
||||
"github.com/storacha-network/go-ucanto/core/policy/selector"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/delegation/policy/literal"
|
||||
"github.com/ucan-wg/go-ucan/delegation/policy/selector"
|
||||
)
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
|
||||
@@ -5,7 +5,8 @@ package policy
|
||||
import (
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
"github.com/storacha-network/go-ucanto/core/policy/selector"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/delegation/policy/selector"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -12,10 +12,11 @@ import (
|
||||
"github.com/ipld/go-ipld-prime/codec/dagjson"
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
basicnode "github.com/ipld/go-ipld-prime/node/basic"
|
||||
"github.com/storacha-network/go-ucanto/core/policy/selector"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/wI2L/jsondiff"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/delegation/policy/selector"
|
||||
)
|
||||
|
||||
//go:embed supported.json
|
||||
|
||||
76
delegation/schema.go
Normal file
76
delegation/schema.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package delegation
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
"github.com/ipld/go-ipld-prime/schema"
|
||||
)
|
||||
|
||||
//go:embed delegation.ipldsch
|
||||
var schemaBytes []byte
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
ts *schema.TypeSystem
|
||||
err error
|
||||
)
|
||||
|
||||
func mustLoadSchema() *schema.TypeSystem {
|
||||
once.Do(func() {
|
||||
ts, err = ipld.LoadSchemaBytes(schemaBytes)
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to load IPLD schema: %s", err))
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
||||
func PayloadType() schema.Type {
|
||||
return mustLoadSchema().TypeByName("Payload")
|
||||
}
|
||||
|
||||
type PayloadModel struct {
|
||||
// Issuer DID (sender)
|
||||
Iss string
|
||||
// Audience DID (receiver)
|
||||
Aud string
|
||||
// Principal that the chain is about (the Subject)
|
||||
// optional: can be nil
|
||||
Sub *string
|
||||
|
||||
// The Command to eventually invoke
|
||||
Cmd string
|
||||
|
||||
// The delegation policy
|
||||
Pol PolicyModel
|
||||
|
||||
// A unique, random nonce
|
||||
Nonce []byte
|
||||
|
||||
// Arbitrary Metadata
|
||||
// optional: can be nil
|
||||
Meta MetaModel
|
||||
|
||||
// "Not before" UTC Unix Timestamp in seconds (valid from), 53-bits integer
|
||||
// optional: can be nil
|
||||
Nbf *int64
|
||||
// The timestamp at which the Invocation becomes invalid
|
||||
// optional: can be nil
|
||||
Exp *int64
|
||||
}
|
||||
|
||||
type MetaModel struct {
|
||||
Keys []string
|
||||
Values map[string]datamodel.Node
|
||||
}
|
||||
|
||||
type PolicyModel struct {
|
||||
}
|
||||
|
||||
func PointerTo[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
60
delegation/schema_test.go
Normal file
60
delegation/schema_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package delegation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
"github.com/ipld/go-ipld-prime/node/bindnode"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSchemaRoundTrip(t *testing.T) {
|
||||
p := &PayloadModel{
|
||||
Iss: "did:key:abc123",
|
||||
Aud: "did:key:def456",
|
||||
Sub: PointerTo(""),
|
||||
Cmd: "/foo/bar",
|
||||
Pol: PolicyModel{}, // TODO: have something here
|
||||
Nonce: []byte("super-random"),
|
||||
Meta: MetaModel{
|
||||
Keys: []string{"foo", "bar"},
|
||||
Values: map[string]datamodel.Node{
|
||||
"foo": bindnode.Wrap(PointerTo("fooo"), nil),
|
||||
"bar": bindnode.Wrap(PointerTo("baaar"), nil),
|
||||
},
|
||||
},
|
||||
Nbf: PointerTo(int64(123456)),
|
||||
Exp: PointerTo(int64(123456)),
|
||||
}
|
||||
|
||||
cborBytes, err := p.EncodeDagCbor()
|
||||
require.NoError(t, err)
|
||||
fmt.Println("cborBytes length", len(cborBytes))
|
||||
fmt.Println("cbor", string(cborBytes))
|
||||
|
||||
jsonBytes, err := p.EncodeDagJson()
|
||||
require.NoError(t, err)
|
||||
fmt.Println("jsonBytes length", len(jsonBytes))
|
||||
fmt.Println("json: ", string(jsonBytes))
|
||||
|
||||
fmt.Println()
|
||||
|
||||
readCbor, err := DecodeDagCbor(cborBytes)
|
||||
require.NoError(t, err)
|
||||
fmt.Println("readCbor", readCbor)
|
||||
require.Equal(t, p, readCbor)
|
||||
|
||||
readJson, err := DecodeDagJson(jsonBytes)
|
||||
require.NoError(t, err)
|
||||
fmt.Println("readJson", readJson)
|
||||
require.Equal(t, p, readJson)
|
||||
}
|
||||
|
||||
func BenchmarkSchemaLoad(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = ipld.LoadSchemaBytes(schemaBytes)
|
||||
}
|
||||
}
|
||||
100
delegation/view.go
Normal file
100
delegation/view.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package delegation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/delegation/policy"
|
||||
"github.com/ucan-wg/go-ucan/did"
|
||||
)
|
||||
|
||||
type View struct {
|
||||
// Issuer DID (sender)
|
||||
Issuer did.DID
|
||||
// Audience DID (receiver)
|
||||
Audience did.DID
|
||||
// Principal that the chain is about (the Subject)
|
||||
Subject did.DID
|
||||
// The Command to eventually invoke
|
||||
Command string
|
||||
// The delegation policy
|
||||
Policy policy.Policy
|
||||
// A unique, random nonce
|
||||
Nonce []byte
|
||||
// Arbitrary Metadata
|
||||
Meta map[string]datamodel.Node
|
||||
// "Not before" UTC Unix Timestamp in seconds (valid from), 53-bits integer
|
||||
NotBefore time.Time
|
||||
// The timestamp at which the Invocation becomes invalid
|
||||
Expiration time.Time
|
||||
}
|
||||
|
||||
// ViewFromModel build a decoded view of the raw IPLD data.
|
||||
// This function also serves as validation.
|
||||
func ViewFromModel(m PayloadModel) (*View, error) {
|
||||
var view View
|
||||
var err error
|
||||
|
||||
view.Issuer, err = did.Parse(m.Iss)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse iss: %w", err)
|
||||
}
|
||||
|
||||
view.Audience, err = did.Parse(m.Aud)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse audience: %w", err)
|
||||
}
|
||||
|
||||
if m.Sub != nil {
|
||||
view.Subject, err = did.Parse(*m.Sub)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse subject: %w", err)
|
||||
}
|
||||
} else {
|
||||
view.Subject = did.Undef
|
||||
}
|
||||
|
||||
// TODO: make that a Command object, and validate it
|
||||
view.Command = m.Cmd
|
||||
|
||||
// TODO: parsing + validation
|
||||
view.Policy = policy.Policy{}
|
||||
|
||||
if len(m.Nonce) == 0 {
|
||||
return nil, fmt.Errorf("nonce is required")
|
||||
}
|
||||
view.Nonce = m.Nonce
|
||||
|
||||
// TODO: copy?
|
||||
view.Meta = m.Meta.Values
|
||||
|
||||
if m.Nbf != nil {
|
||||
view.NotBefore = time.Unix(*m.Nbf, 0)
|
||||
}
|
||||
|
||||
if m.Exp != nil {
|
||||
view.Expiration = time.Unix(*m.Exp, 0)
|
||||
}
|
||||
|
||||
return &view, nil
|
||||
}
|
||||
|
||||
func (view *View) Capability() *Capability {
|
||||
return &Capability{
|
||||
Subject: view.Subject,
|
||||
Command: view.Command,
|
||||
Policy: view.Policy,
|
||||
}
|
||||
}
|
||||
|
||||
// Capability is a subset of a delegation formed by the triple (subject, command, policy).
|
||||
type Capability struct {
|
||||
// Principal that the chain is about (the Subject)
|
||||
Subject did.DID
|
||||
// The Command to eventually invoke
|
||||
Command string
|
||||
// The delegation policy
|
||||
Policy policy.Policy
|
||||
}
|
||||
12
go.mod
12
go.mod
@@ -3,24 +3,30 @@ module github.com/ucan-wg/go-ucan
|
||||
go 1.22.1
|
||||
|
||||
require (
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/ipfs/go-cid v0.4.1
|
||||
github.com/ipld/go-ipld-prime v0.21.0
|
||||
github.com/multiformats/go-multibase v0.0.3
|
||||
github.com/multiformats/go-varint v0.0.6
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/wI2L/jsondiff v0.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/ipfs/go-cid v0.4.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.0.3 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.0.3 // indirect
|
||||
github.com/multiformats/go-multihash v0.2.3 // indirect
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/polydawn/refmt v0.89.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/tidwall/gjson v1.17.1 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
golang.org/x/crypto v0.1.0 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
14
go.sum
14
go.sum
@@ -5,6 +5,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
@@ -55,7 +57,19 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
|
||||
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/wI2L/jsondiff v0.6.0 h1:zrsH3FbfVa3JO9llxrcDy/XLkYPLgoMX6Mz3T2PP2AI=
|
||||
github.com/wI2L/jsondiff v0.6.0/go.mod h1:D6aQ5gKgPF9g17j+E9N7aasmU1O+XvfmWm1y8UMmNpw=
|
||||
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
|
||||
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
||||
Reference in New Issue
Block a user