24 Commits

Author SHA1 Message Date
Michael Muré
a82bce556f Merge pull request #108 from ucan-wg/cont-test
container: add a helper for test only
2025-02-27 15:00:47 +01:00
Michael Muré
a54d66afe5 Merge pull request #110 from ucan-wg/cleanups
minor cleanups
2025-02-27 14:58:24 +01:00
Michael Muré
14a57d7391 Merge pull request #109 from ucan-wg/downgrade-libp2p
deps: downgrade libp2p
2025-02-27 14:58:17 +01:00
Michael Muré
68469db91a minor cleanups 2025-02-27 14:35:53 +01:00
Michael Muré
cc1d68be0c deps: downgrade libp2p
We only use go-libp2p for the crypto wrappers (github.com/libp2p/go-libp2p/core/crypto), and those have not changed in a while.

We don't need the most recent version of go-libp2p. On the other hand, a too recent version can easily mess with project that aim for an older version of libp2p (often transitively). This PR gives some leeway for version resolution.
2025-02-27 14:28:23 +01:00
Michael Muré
6d3846ac62 container: add a helper for test only 2025-02-27 14:27:02 +01:00
Steve Moyer
6aa33b1547 Merge pull request #107 from ucan-wg/tinygo
fix(policy): make 53-bit limits portable across platforms
2025-02-24 06:25:06 -05:00
Steve Moyer
9589cc8b44 feat(tinygo): make 53-bit limits portable across platforms 2025-02-21 11:03:33 -05:00
Michael Muré
879c0ab03b Merge pull request #106 from ucan-wg/cont-type
container: use the correct type in GetAllDelegations
2025-02-03 15:13:05 +01:00
Michael Muré
fe14765c8d container: use the correct type in GetAllDelegations 2025-02-03 15:02:31 +01:00
Michael Muré
1b28cb49bf Merge pull request #105 from ucan-wg/containertest
rename testvectors into containertest to match previous namings
2025-01-29 15:04:33 +01:00
Michael Muré
e1fc838caf rename testvectors into containertest to match previous namings 2025-01-29 14:46:01 +01:00
Michael Muré
f29b9e94fc Merge pull request #104 from ucan-wg/bundle
token: ditch the generic bundle in favor of specialized struct
2025-01-29 14:37:29 +01:00
Michael Muré
506ed21b94 token: ditch the generic bundle in favor of specialized struct
It's kust cleaner that way, the generic has no upside.
2025-01-29 14:28:13 +01:00
Michael Muré
126177b9e5 Merge pull request #103 from ucan-wg/dlg-is
delegation: add predicates to check if a delegation is a root or powe…
2025-01-29 14:11:29 +01:00
Michael Muré
2bddab8b0c delegation: add predicates to check if a delegation is a root or powerline 2025-01-29 14:07:49 +01:00
Michael Muré
45ead12131 Merge pull request #102 from ucan-wg/cont-keep-sealed
container: Reader should keep around and expose the sealed bytes
2025-01-23 18:06:41 +01:00
Michael Muré
9d5e170409 Merge pull request #101 from ucan-wg/cont-testing
container: expose test vectors for easier testing
2025-01-23 18:06:27 +01:00
Michael Muré
9d047f038d container: Reader should keep around and expose the sealed bytes 2025-01-23 17:13:10 +01:00
Michael Muré
4c5afcb084 container: expose test vectors for easier testing 2025-01-23 17:10:34 +01:00
Michael Muré
e218b49577 Merge pull request #100 from ucan-wg/pol-neq
policy: implement the missing '!='
2025-01-23 12:38:17 +01:00
Michael Muré
4c81ac778e policy: fix tests now that selector evaluation is clearer
https://github.com/ucan-wg/delegation/pull/15
https://github.com/ucan-wg/delegation/pull/16
2025-01-23 12:28:02 +01:00
Michael Muré
7ae65e7c8e policy: fix some code style 2025-01-22 17:30:28 +01:00
Michael Muré
7f9cb6426c policy: implement the missing '!='
https://github.com/ucan-wg/delegation/pull/15
2025-01-22 14:12:41 +01:00
36 changed files with 449 additions and 131 deletions

View File

@@ -57,7 +57,7 @@ Not implemented yet:
Besides that, `go-ucan` also includes:
- a simplified [DID](https://www.w3.org/TR/did-core/) and [did-key](https://w3c-ccg.github.io/did-method-key/) implementation
- a [token container](https://github.com/ucan-wg/go-ucan/tree/v1/pkg/container) with CBOR and CAR format, to package and carry tokens together
- a [token container](https://github.com/ucan-wg/go-ucan/tree/v1/pkg/container) with CBOR and CAR format, to package and carry tokens together, see [SPEC](pkg/container/SPEC.md)
- support for encrypted values in token's metadata
## Getting Help

10
go.mod
View File

@@ -4,10 +4,10 @@ go 1.23
require (
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0
github.com/ipfs/go-cid v0.4.1
github.com/ipfs/go-cid v0.5.0
github.com/ipld/go-ipld-prime v0.21.0
github.com/lestrrat-go/jwx/v2 v2.1.1
github.com/libp2p/go-libp2p v0.36.3
github.com/lestrrat-go/jwx/v2 v2.1.3
github.com/libp2p/go-libp2p v0.33.0
github.com/mr-tron/base58 v1.2.0
github.com/multiformats/go-multibase v0.2.0
github.com/multiformats/go-multicodec v0.9.0
@@ -22,7 +22,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.6 // indirect
@@ -36,7 +36,7 @@ require (
github.com/segmentio/asm v1.2.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
golang.org/x/sys v0.29.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
google.golang.org/protobuf v1.36.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect

29
go.sum
View File

@@ -16,14 +16,14 @@ 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=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg=
github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk=
github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -36,14 +36,14 @@ github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCG
github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jwx/v2 v2.1.1 h1:Y2ltVl8J6izLYFs54BVcpXLv5msSW4o8eXwnzZLI32E=
github.com/lestrrat-go/jwx/v2 v2.1.1/go.mod h1:4LvZg7oxu6Q5VJwn7Mk/UwooNRnTHUpXBj2C4j3HNx0=
github.com/lestrrat-go/jwx/v2 v2.1.3 h1:Ud4lb2QuxRClYAmRleF50KrbKIoM1TddXgBrneT5/Jo=
github.com/lestrrat-go/jwx/v2 v2.1.3/go.mod h1:q6uFgbgZfEmQrfJfrCo90QcQOcXFMfbI/fO0NqRtvZo=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
github.com/libp2p/go-libp2p v0.36.3 h1:NHz30+G7D8Y8YmznrVZZla0ofVANrvBl2c+oARfMeDQ=
github.com/libp2p/go-libp2p v0.36.3/go.mod h1:4Y5vFyCUiJuluEPmpnKYf6WFx5ViKPUYs/ixe9ANFZ8=
github.com/libp2p/go-libp2p v0.33.0 h1:yTPSr8sJRbfeEYXyeN8VPVSlTlFjtMUwGDRniwaf/xQ=
github.com/libp2p/go-libp2p v0.33.0/go.mod h1:RIJFRQVUBKy82dnW7J5f1homqqv6NcsDJAl3e7CRGfE=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
@@ -52,8 +52,8 @@ github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aG
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ=
github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII=
github.com/multiformats/go-multiaddr v0.12.2 h1:9G9sTY/wCYajKa9lyfWPmpZAwe6oV+Wb1zcmMS1HG24=
github.com/multiformats/go-multiaddr v0.12.2/go.mod h1:GKyaTYjZRdcUhyOetrxTk9z0cW+jA/YrnqTOvKgi44M=
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg=
@@ -89,17 +89,16 @@ github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvS
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -0,0 +1,21 @@
package containertest
import _ "embed"
//go:embed Base64StdPadding
var Base64StdPadding string
//go:embed Base64StdPaddingGzipped
var Base64StdPaddingGzipped string
//go:embed Base64URL
var Base64URL string
//go:embed Base64URLGzipped
var Base64URLGzipped string
//go:embed Bytes
var Bytes []byte
//go:embed BytesGzipped
var BytesGzipped []byte

View File

@@ -21,7 +21,12 @@ var ErrNotFound = fmt.Errorf("not found")
var ErrMultipleInvocations = fmt.Errorf("multiple invocations")
// Reader is a token container reader. It exposes the tokens conveniently decoded.
type Reader map[cid.Cid]token.Token
type Reader map[cid.Cid]bundle
type bundle struct {
sealed []byte
token token.Token
}
// FromBytes decodes a container from a []byte
func FromBytes(data []byte) (Reader, error) {
@@ -92,11 +97,36 @@ func FromReader(r io.Reader) (Reader, error) {
// GetToken returns an arbitrary decoded token, from its CID.
// If not found, ErrNotFound is returned.
func (ctn Reader) GetToken(cid cid.Cid) (token.Token, error) {
tkn, ok := ctn[cid]
bndl, ok := ctn[cid]
if !ok {
return nil, ErrNotFound
}
return tkn, nil
return bndl.token, nil
}
// GetSealed returns an arbitrary sealed token, from its CID.
// If not found, ErrNotFound is returned.
func (ctn Reader) GetSealed(cid cid.Cid) ([]byte, error) {
bndl, ok := ctn[cid]
if !ok {
return nil, ErrNotFound
}
return bndl.sealed, nil
}
// GetAllTokens return all the tokens in the container.
func (ctn Reader) GetAllTokens() iter.Seq[token.Bundle] {
return func(yield func(token.Bundle) bool) {
for c, bndl := range ctn {
if !yield(token.Bundle{
Cid: c,
Decoded: bndl.token,
Sealed: bndl.sealed,
}) {
return
}
}
}
}
// GetDelegation is the same as GetToken but only return a delegation.Token, with the right type.
@@ -113,11 +143,15 @@ func (ctn Reader) GetDelegation(cid cid.Cid) (*delegation.Token, error) {
}
// GetAllDelegations returns all the delegation.Token in the container.
func (ctn Reader) GetAllDelegations() iter.Seq2[cid.Cid, *delegation.Token] {
return func(yield func(cid.Cid, *delegation.Token) bool) {
for c, t := range ctn {
if t, ok := t.(*delegation.Token); ok {
if !yield(c, t) {
func (ctn Reader) GetAllDelegations() iter.Seq[delegation.Bundle] {
return func(yield func(delegation.Bundle) bool) {
for c, bndl := range ctn {
if t, ok := bndl.token.(*delegation.Token); ok {
if !yield(delegation.Bundle{
Cid: c,
Decoded: t,
Sealed: bndl.sealed,
}) {
return
}
}
@@ -130,8 +164,8 @@ func (ctn Reader) GetAllDelegations() iter.Seq2[cid.Cid, *delegation.Token] {
// If more than one invocation exists, ErrMultipleInvocations is returned.
func (ctn Reader) GetInvocation() (*invocation.Token, error) {
var res *invocation.Token
for _, t := range ctn {
if inv, ok := t.(*invocation.Token); ok {
for _, bndl := range ctn {
if inv, ok := bndl.token.(*invocation.Token); ok {
if res != nil {
return nil, ErrMultipleInvocations
}
@@ -145,11 +179,15 @@ func (ctn Reader) GetInvocation() (*invocation.Token, error) {
}
// GetAllInvocations returns all the invocation.Token in the container.
func (ctn Reader) GetAllInvocations() iter.Seq2[cid.Cid, *invocation.Token] {
return func(yield func(cid.Cid, *invocation.Token) bool) {
for c, t := range ctn {
if t, ok := t.(*invocation.Token); ok {
if !yield(c, t) {
func (ctn Reader) GetAllInvocations() iter.Seq[invocation.Bundle] {
return func(yield func(invocation.Bundle) bool) {
for c, bndl := range ctn {
if t, ok := bndl.token.(*invocation.Token); ok {
if !yield(invocation.Bundle{
Cid: c,
Decoded: t,
Sealed: bndl.sealed,
}) {
return
}
}
@@ -162,6 +200,19 @@ func (ctn Reader) addToken(data []byte) error {
if err != nil {
return err
}
ctn[c] = tkn
ctn[c] = bundle{
sealed: data,
token: tkn,
}
return nil
}
// ToWriter convert a container Reader into a Writer.
// Most likely, you only want to use this in tests for convenience.
func (ctn Reader) ToWriter() Writer {
writer := NewWriter()
for _, bndl := range ctn {
writer.AddSealed(bndl.sealed)
}
return writer
}

View File

@@ -36,7 +36,7 @@ func TestContainerRoundTrip(t *testing.T) {
{"Base64StdPaddingGzippedWriter", headerBase64StdPaddingGzip, Writer.ToBase64StdPaddingGzippedWriter},
{"Base64URL", headerBase64URL, Writer.ToBase64URL},
{"Base64URLWriter", headerBase64URL, Writer.ToBase64URLWriter},
{"Base64URLGzip", headerBase64URLGzip, Writer.ToBase64URLGzip},
{"Base64URLGzipped", headerBase64URLGzip, Writer.ToBase64URLGzipped},
{"Base64URLGzipWriter", headerBase64URLGzip, Writer.ToBase64URLGzipWriter},
} {
t.Run(tc.name, func(t *testing.T) {

View File

@@ -74,7 +74,7 @@ func (ctn Writer) ToBase64URLWriter(w io.Writer) error {
}
// ToBase64URL encode the container into pre-gzipped base64 string, with URL-safe encoding and no padding.
func (ctn Writer) ToBase64URLGzip() (string, error) {
func (ctn Writer) ToBase64URLGzipped() (string, error) {
return ctn.toString(headerBase64URLGzip)
}
@@ -120,3 +120,20 @@ func (ctn Writer) toWriter(header header, w io.Writer) (err error) {
return ipld.EncodeStreaming(encoder, node, cbor.Encode)
}
// ToReader convert a container Writer into a Reader.
// Most likely, you only want to use this in tests for convenience.
// This is not optimized and can panic.
func (ctn Writer) ToReader() Reader {
data, err := ctn.ToBytes()
if err != nil {
panic(err)
}
reader, err := FromBytes(data)
if err != nil {
panic(err)
}
return reader
}

View File

@@ -81,7 +81,7 @@ func statementFromIPLD(path string, node datamodel.Node) (Statement, error) {
}
case 3:
switch op {
case KindEqual, KindLessThan, KindLessThanOrEqual, KindGreaterThan, KindGreaterThanOrEqual:
case KindEqual, KindNotEqual, KindLessThan, KindLessThanOrEqual, KindGreaterThan, KindGreaterThanOrEqual:
sel, err := arg2AsSelector(op)
if err != nil {
return nil, err

View File

@@ -21,10 +21,31 @@ func TestIpldRoundTrip(t *testing.T) {
]
]`
// must contain all the operators
const allOps = `
[
["and", [
["==", ".foo1", ".bar1"],
["!=", ".foo2", ".bar2"]
]],
["or", [
[">", ".foo5", 5.2],
[">=", ".foo6", 6.2]
]],
["not", ["like", ".foo7", "*@example.com"]],
["all", ".foo8",
["<", ".foo3", 3]
],
["any", ".foo9",
["<=", ".foo4", 4]
]
]`
for _, tc := range []struct {
name, dagJsonStr string
}{
{"illustrativeExample", illustrativeExample},
{"allOps", allOps},
} {
nodes, err := ipld.Decode([]byte(tc.dagJsonStr), dagjson.Decode)
require.NoError(t, err)

View File

@@ -9,9 +9,9 @@ import (
const (
// MaxInt53 represents the maximum safe integer in JavaScript (2^53 - 1)
MaxInt53 = 9007199254740991
MaxInt53 int64 = 9007199254740991
// MinInt53 represents the minimum safe integer in JavaScript (-2^53 + 1)
MinInt53 = -9007199254740991
MinInt53 int64 = -9007199254740991
)
func ValidateIntegerBoundsIPLD(node ipld.Node) error {

View File

@@ -185,7 +185,7 @@ func anyAssemble(val any) qp.Assemble {
return qp.Int(i)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
u := rv.Uint()
if u > limits.MaxInt53 {
if u > uint64(limits.MaxInt53) {
panic(fmt.Sprintf("unsigned integer %d exceeds safe bounds", u))
}
return qp.Int(int64(u))

View File

@@ -82,6 +82,17 @@ func matchStatement(cur Statement, node ipld.Node) (_ matchResult, leafMost Stat
}
return boolToRes(datamodel.DeepEqual(s.value, res))
}
case KindNotEqual:
if s, ok := cur.(equality); ok {
res, err := s.selector.Select(node)
if err != nil {
return matchResultNoData, cur
}
if res == nil { // optional selector didn't match
return matchResultOptionalNoData, nil
}
return boolToRes(!datamodel.DeepEqual(s.value, res))
}
case KindGreaterThan:
if s, ok := cur.(equality); ok {
res, err := s.selector.Select(node)

View File

@@ -16,7 +16,7 @@ import (
func TestMatch(t *testing.T) {
t.Run("equality", func(t *testing.T) {
t.Run("string", func(t *testing.T) {
t.Run("eq string", func(t *testing.T) {
nd := literal.String("test")
pol := MustConstruct(Equal(".", literal.String("test")))
@@ -35,7 +35,7 @@ func TestMatch(t *testing.T) {
require.Equal(t, pol[0], leaf)
})
t.Run("int", func(t *testing.T) {
t.Run("eq int", func(t *testing.T) {
nd := literal.Int(138)
pol := MustConstruct(Equal(".", literal.Int(138)))
@@ -54,7 +54,7 @@ func TestMatch(t *testing.T) {
require.Equal(t, pol[0], leaf)
})
t.Run("float", func(t *testing.T) {
t.Run("eq float", func(t *testing.T) {
nd := literal.Float(1.138)
pol := MustConstruct(Equal(".", literal.Float(1.138)))
@@ -73,7 +73,7 @@ func TestMatch(t *testing.T) {
require.Equal(t, pol[0], leaf)
})
t.Run("IPLD Link", func(t *testing.T) {
t.Run("eq IPLD Link", func(t *testing.T) {
l0 := cidlink.Link{Cid: cid.MustParse("bafybeif4owy5gno5lwnixqm52rwqfodklf76hsetxdhffuxnplvijskzqq")}
l1 := cidlink.Link{Cid: cid.MustParse("bafkreifau35r7vi37tvbvfy3hdwvgb4tlflqf7zcdzeujqcjk3rsphiwte")}
@@ -95,7 +95,7 @@ func TestMatch(t *testing.T) {
require.Equal(t, pol[0], leaf)
})
t.Run("string in map", func(t *testing.T) {
t.Run("eq string in map", func(t *testing.T) {
nd, _ := literal.Map(map[string]any{
"foo": "bar",
})
@@ -121,7 +121,7 @@ func TestMatch(t *testing.T) {
require.Equal(t, pol[0], leaf)
})
t.Run("string in list", func(t *testing.T) {
t.Run("eq string in list", func(t *testing.T) {
nd, _ := literal.List([]any{"foo"})
pol := MustConstruct(Equal(".[0]", literal.String("foo")))
@@ -134,6 +134,132 @@ func TestMatch(t *testing.T) {
require.False(t, ok)
require.Equal(t, pol[0], leaf)
})
t.Run("neq string", func(t *testing.T) {
nd := literal.String("test")
pol := MustConstruct(NotEqual(".", literal.String("test")))
ok, leaf := pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
pol = MustConstruct(NotEqual(".", literal.String("test2")))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
pol = MustConstruct(NotEqual(".", literal.Int(138)))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
})
t.Run("neq int", func(t *testing.T) {
nd := literal.Int(138)
pol := MustConstruct(NotEqual(".", literal.Int(138)))
ok, leaf := pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
pol = MustConstruct(NotEqual(".", literal.Int(1138)))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
pol = MustConstruct(NotEqual(".", literal.String("138")))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
})
t.Run("neq float", func(t *testing.T) {
nd := literal.Float(1.138)
pol := MustConstruct(NotEqual(".", literal.Float(1.138)))
ok, leaf := pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
pol = MustConstruct(NotEqual(".", literal.Float(11.38)))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
pol = MustConstruct(NotEqual(".", literal.String("138")))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
})
t.Run("neq IPLD Link", func(t *testing.T) {
l0 := cidlink.Link{Cid: cid.MustParse("bafybeif4owy5gno5lwnixqm52rwqfodklf76hsetxdhffuxnplvijskzqq")}
l1 := cidlink.Link{Cid: cid.MustParse("bafkreifau35r7vi37tvbvfy3hdwvgb4tlflqf7zcdzeujqcjk3rsphiwte")}
nd := literal.Link(l0)
pol := MustConstruct(NotEqual(".", literal.Link(l0)))
ok, leaf := pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
pol = MustConstruct(NotEqual(".", literal.Link(l1)))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
pol = MustConstruct(NotEqual(".", literal.String("bafybeif4owy5gno5lwnixqm52rwqfodklf76hsetxdhffuxnplvijskzqq")))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
})
t.Run("neq string in map", func(t *testing.T) {
nd, _ := literal.Map(map[string]any{
"foo": "bar",
})
pol := MustConstruct(NotEqual(".foo", literal.String("bar")))
ok, leaf := pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
pol = MustConstruct(NotEqual(".[\"foo\"]", literal.String("bar")))
ok, leaf = pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
pol = MustConstruct(NotEqual(".foo", literal.String("baz")))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
// missing data will fail, as not optional
pol = MustConstruct(NotEqual(".foobar", literal.String("bar")))
ok, leaf = pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
})
t.Run("neq string in list", func(t *testing.T) {
nd, _ := literal.List([]any{"foo"})
pol := MustConstruct(NotEqual(".[0]", literal.String("foo")))
ok, leaf := pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
pol = MustConstruct(NotEqual(".[0]", literal.String("bar")))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
// missing data will fail, as not optional
pol = MustConstruct(NotEqual(".[1]", literal.String("foo")))
ok, leaf = pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
})
})
t.Run("inequality", func(t *testing.T) {
@@ -245,20 +371,61 @@ func TestMatch(t *testing.T) {
require.False(t, ok)
require.Equal(t, pol[0], leaf)
})
t.Run("lt float", func(t *testing.T) {
nd := literal.Float(1.38)
pol := MustConstruct(LessThan(".", literal.Float(1)))
ok, leaf := pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
pol = MustConstruct(LessThan(".", literal.Float(2)))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
})
t.Run("lte float", func(t *testing.T) {
nd := literal.Float(1.38)
pol := MustConstruct(LessThanOrEqual(".", literal.Float(1)))
ok, leaf := pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
pol = MustConstruct(GreaterThanOrEqual(".", literal.Float(1.38)))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
pol = MustConstruct(LessThanOrEqual(".", literal.Float(2)))
ok, leaf = pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
})
})
t.Run("negation", func(t *testing.T) {
nd := literal.Bool(false)
nd, _ := literal.Map(map[string]any{
"foo": false,
})
pol := MustConstruct(Not(Equal(".", literal.Bool(true))))
pol := MustConstruct(Not(Equal(".foo", literal.Bool(true))))
ok, leaf := pol.Match(nd)
require.True(t, ok)
require.Nil(t, leaf)
pol = MustConstruct(Not(Equal(".", literal.Bool(false))))
pol = MustConstruct(Not(Equal(".foo", literal.Bool(false))))
ok, leaf = pol.Match(nd)
require.False(t, ok)
require.Equal(t, pol[0], leaf)
// missing data will fail, as not optional
pol = MustConstruct(Not(Equal(".foobar", literal.Bool(true))))
ok, leaf = pol.Match(nd)
require.False(t, ok)
require.Equal(t, MustConstruct(Equal(".foobar", literal.Bool(true)))[0], leaf)
})
t.Run("conjunction", func(t *testing.T) {
@@ -482,6 +649,7 @@ func FuzzMatch(f *testing.F) {
f.Add([]byte(`[["all", ".reviewer", ["like", ".email", "*@example.com"]]]`), []byte(`{"reviewer": [{"email": "alice@example.com"}, {"email": "bob@example.com"}]}`))
f.Add([]byte(`[["any", ".tags", ["or", [["==", ".", "news"], ["==", ".", "press"]]]]]`), []byte(`{"tags": ["news", "press"]}`))
f.Add([]byte(`[["==", ".name", "Alice"]]`), []byte(`{"name": "Alice"}`))
f.Add([]byte(`[["!=", ".name", "Alice"]]`), []byte(`{"name": "Alice"}`))
f.Add([]byte(`[[">", ".age", 30]]`), []byte(`{"age": 31}`))
f.Add([]byte(`[["<=", ".height", 180]]`), []byte(`{"height": 170}`))
f.Add([]byte(`[["not", ["==", ".status", "inactive"]]]`), []byte(`{"status": "active"}`))

View File

@@ -14,6 +14,7 @@ import (
const (
KindEqual = "==" // implemented by equality
KindNotEqual = "!=" // implemented by equality
KindGreaterThan = ">" // implemented by equality
KindGreaterThanOrEqual = ">=" // implemented by equality
KindLessThan = "<" // implemented by equality
@@ -87,6 +88,13 @@ func Equal(selector string, value ipld.Node) Constructor {
}
}
func NotEqual(selector string, value ipld.Node) Constructor {
return func() (Statement, error) {
sel, err := selpkg.Parse(selector)
return equality{kind: KindNotEqual, selector: sel, value: value}, err
}
}
func GreaterThan(selector string, value ipld.Node) Constructor {
return func() (Statement, error) {
sel, err := selpkg.Parse(selector)
@@ -125,7 +133,7 @@ func (n negation) Kind() string {
func (n negation) String() string {
child := n.statement.String()
return fmt.Sprintf(`["%s", "%s"]`, n.Kind(), strings.ReplaceAll(child, "\n", "\n "))
return fmt.Sprintf(`["%s", %s]`, n.Kind(), strings.ReplaceAll(child, "\n", "\n "))
}
func Not(cstor Constructor) Constructor {
@@ -149,7 +157,7 @@ func (c connective) String() string {
for i, statement := range c.statements {
childs[i] = strings.ReplaceAll(statement.String(), "\n", "\n ")
}
return fmt.Sprintf("[\"%s\", [\n %s]]\n", c.kind, strings.Join(childs, ",\n "))
return fmt.Sprintf("[\"%s\", [\n %s\n]]", c.kind, strings.Join(childs, ",\n "))
}
func And(cstors ...Constructor) Constructor {
@@ -208,7 +216,7 @@ func (n quantifier) Kind() string {
func (n quantifier) String() string {
child := n.statement.String()
return fmt.Sprintf("[\"%s\", \"%s\",\n %s]", n.Kind(), n.selector, strings.ReplaceAll(child, "\n", "\n "))
return fmt.Sprintf("[\"%s\", \"%s\",\n %s\n]", n.Kind(), n.selector, strings.ReplaceAll(child, "\n", "\n "))
}
func All(selector string, cstor Constructor) Constructor {

View File

@@ -28,12 +28,14 @@ func ExamplePolicy() {
// [
// ["==", ".status", "draft"],
// ["all", ".reviewer",
// ["like", ".email", "*@example.com"]],
// ["like", ".email", "*@example.com"]
// ],
// ["any", ".tags",
// ["or", [
// ["==", ".", "news"],
// ["==", ".", "press"]]]
// ]
// ["==", ".", "press"]
// ]]
// ]
// ]
}
@@ -59,12 +61,14 @@ func ExamplePolicy_accumulate() {
// [
// ["==", ".status", "draft"],
// ["all", ".reviewer",
// ["like", ".email", "*@example.com"]],
// ["like", ".email", "*@example.com"]
// ],
// ["any", ".tags",
// ["or", [
// ["==", ".", "news"],
// ["==", ".", "press"]]]
// ]
// ["==", ".", "press"]
// ]]
// ]
// ]
}

View File

@@ -2,6 +2,7 @@ package policytest
import (
"github.com/ipld/go-ipld-prime"
"github.com/ucan-wg/go-ucan/pkg/args"
"github.com/ucan-wg/go-ucan/pkg/policy"
"github.com/ucan-wg/go-ucan/pkg/policy/literal"
@@ -10,9 +11,8 @@ import (
// EmptyPolicy provides a Policy with no statements.
var EmptyPolicy = policy.Policy{}
// ExampleValidationPolicy provides a instantiated SpecPolicy containing the
// statements that are included in the second code block of the [Validation]
// section of the delegation specification.
// SpecPolicy provides a valid Policy containing the statements that are included
// in the second code block of the [Validation] section of the delegation specification.
//
// [Validation]: https://github.com/ucan-wg/delegation/tree/v1_ipld#validation
var SpecPolicy = policy.MustConstruct(
@@ -24,8 +24,8 @@ var SpecPolicy = policy.MustConstruct(
// specification has been finished/merged.
// SpecValidArguments provides valid, instantiated Arguments containing
// the key/value pairs that are included in portion of the the second code
// block of the [Validation] section of the delegation specification.
// the key/value pairs that are included in portion of the second code block
// of the [Validation] section of the delegation specification.
//
// [Validation]: https://github.com/ucan-wg/delegation/tree/v1_ipld#validation
var SpecValidArguments = args.NewBuilder().
@@ -41,8 +41,8 @@ var SpecValidArguments = args.NewBuilder().
var specValidArgumentsIPLD = mustIPLD(SpecValidArguments)
// SpecInvalidArguments provides invalid, instantiated Arguments containing
// the key/value pairs that are included in portion of the the second code
// block of the [Validation] section of the delegation specification.
// the key/value pairs that are included in portion of the second code block
// of the [Validation] section of the delegation specification.
//
// [Validation]: https://github.com/ucan-wg/delegation/tree/v1_ipld#validation
var SpecInvalidArguments = args.NewBuilder().

View File

@@ -68,7 +68,7 @@ func Parse(str string) (Selector, error) {
if err != nil {
return nil, newParseError("invalid index", str, col, tok)
}
if idx > limits.MaxInt53 || idx < limits.MinInt53 {
if int64(idx) > limits.MaxInt53 || int64(idx) < limits.MinInt53 {
return nil, newParseError(fmt.Sprintf("index %d exceeds safe integer bounds", idx), str, col, tok)
}
sel = append(sel, segment{str: tok, optional: opt, index: idx})
@@ -173,37 +173,37 @@ func tokenize(str string) []string {
return toks
}
type parseerr struct {
type parseErr struct {
msg string
src string
col int
tok string
}
func (p parseerr) Name() string {
func (p parseErr) Name() string {
return "ParseError"
}
func (p parseerr) Message() string {
func (p parseErr) Message() string {
return p.msg
}
func (p parseerr) Column() int {
func (p parseErr) Column() int {
return p.col
}
func (p parseerr) Error() string {
func (p parseErr) Error() string {
return p.msg
}
func (p parseerr) Source() string {
func (p parseErr) Source() string {
return p.src
}
func (p parseerr) Token() string {
func (p parseErr) Token() string {
return p.tok
}
func newParseError(message string, source string, column int, token string) error {
return parseerr{message, source, column, token}
return parseErr{message, source, column, token}
}

View File

@@ -19,7 +19,7 @@ type Selector []segment
// Select perform the selection described by the selector on the input IPLD DAG.
// Select can return:
// - exactly one matched IPLD node
// - a resolutionerr error if not being able to resolve to a node
// - a resolutionErr error if not being able to resolve to a node
// - nil and no errors, if the selector couldn't match on an optional segment (with ?).
func (s Selector) Select(subject ipld.Node) (ipld.Node, error) {
return resolve(s, subject, nil)
@@ -316,27 +316,27 @@ func kindString(n datamodel.Node) string {
return n.Kind().String()
}
type resolutionerr struct {
type resolutionErr struct {
msg string
at []string
}
func (r resolutionerr) Name() string {
func (r resolutionErr) Name() string {
return "ResolutionError"
}
func (r resolutionerr) Message() string {
func (r resolutionErr) Message() string {
return fmt.Sprintf("can not resolve path: .%s", strings.Join(r.at, "."))
}
func (r resolutionerr) At() []string {
func (r resolutionErr) At() []string {
return r.at
}
func (r resolutionerr) Error() string {
func (r resolutionErr) Error() string {
return r.Message()
}
func newResolutionError(message string, at []string) error {
return resolutionerr{message, at}
return resolutionErr{message, at}
}

View File

@@ -133,7 +133,7 @@ func TestSelect(t *testing.T) {
require.Error(t, err)
require.Empty(t, res)
require.ErrorAs(t, err, &resolutionerr{}, "error should be a resolution error")
require.ErrorAs(t, err, &resolutionErr{}, "error should be a resolution error")
})
t.Run("optional not exists", func(t *testing.T) {
@@ -351,7 +351,7 @@ func FuzzParseAndSelect(f *testing.F) {
// look for panic()
_, err = sel.Select(node)
if err != nil && !errors.As(err, &resolutionerr{}) {
if err != nil && !errors.As(err, &resolutionErr{}) {
// not normal, we should only have resolution errors
t.Fatal(err)
}

View File

@@ -83,7 +83,7 @@ func New(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, sub d
}
// Root creates a validated UCAN delegation Token from the provided parameters and options.
// This is typically used to create and give a power to an agent.
// This is typically used to create and give power to an agent.
//
// You can read it as "(issuer) allows (audience) to perform (cmd+pol) on itself".
func Root(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, opts ...Option) (*Token, error) {
@@ -154,6 +154,16 @@ func (t *Token) Expiration() *time.Time {
return t.expiration
}
// IsRoot tells if the token is a root delegation.
func (t *Token) IsRoot() bool {
return t.issuer == t.subject
}
// IsPowerline tells if the token is a powerline delegation.
func (t *Token) IsPowerline() bool {
return t.subject == did.Undef
}
// IsValidNow verifies that the token can be used at the current time, based on expiration or "not before" fields.
// This does NOT do any other kind of verifications.
func (t *Token) IsValidNow() bool {

View File

@@ -20,39 +20,16 @@ const (
subJectCmd = "/foo/bar"
subjectPol = `
[
[
"==",
".status",
"draft"
],
[
"all",
".reviewer",
[
"like",
".email",
"*@example.com"
]
],
[
"any",
".tags",
[
"or",
[
[
"==",
".",
"news"
],
[
"==",
".",
"press"
]
]
]
]
["==", ".status", "draft"],
["all", ".reviewer",
["like", ".email", "*@example.com"]
],
["any", ".tags",
["or", [
["==", ".", "news"],
["==", ".", "press"]
]]
]
]
`
@@ -80,6 +57,9 @@ func TestConstructors(t *testing.T) {
)
require.NoError(t, err)
require.False(t, tkn.IsRoot())
require.False(t, tkn.IsPowerline())
data, err := tkn.ToDagJson(didtest.PersonaAlice.PrivKey())
require.NoError(t, err)
@@ -97,6 +77,9 @@ func TestConstructors(t *testing.T) {
)
require.NoError(t, err)
require.True(t, tkn.IsRoot())
require.False(t, tkn.IsPowerline())
data, err := tkn.ToDagJson(didtest.PersonaAlice.PrivKey())
require.NoError(t, err)
@@ -114,6 +97,9 @@ func TestConstructors(t *testing.T) {
)
require.NoError(t, err)
require.False(t, tkn.IsRoot())
require.True(t, tkn.IsPowerline())
data, err := tkn.ToDagJson(didtest.PersonaAlice.PrivKey())
require.NoError(t, err)

View File

@@ -242,7 +242,7 @@ func (g *generator) writeGoFile() error {
Println("}")
Println()
Println("var AllBundles = []*delegation.Bundle{")
Println("var AllBundles = []delegation.Bundle{")
for _, d := range g.dlgs {
Printf("\t%sBundle,\n", d.name)
}

View File

@@ -38,7 +38,7 @@ var fs embed.FS
var _ delegation.Loader = (*DelegationLoader)(nil)
type DelegationLoader struct {
bundles map[cid.Cid]*delegation.Bundle
bundles map[cid.Cid]delegation.Bundle
}
var (
@@ -75,7 +75,7 @@ func loadDelegations() (*DelegationLoader, error) {
return nil, err
}
bundles := make(map[cid.Cid]*delegation.Bundle, len(dirEntries))
bundles := make(map[cid.Cid]delegation.Bundle, len(dirEntries))
for _, dirEntry := range dirEntries {
data, err := fs.ReadFile(filepath.Join(TokenDir, dirEntry.Name()))
@@ -88,7 +88,7 @@ func loadDelegations() (*DelegationLoader, error) {
return nil, err
}
bundles[id] = &delegation.Bundle{Cid: id, Decoded: tkn, Sealed: data}
bundles[id] = delegation.Bundle{Cid: id, Decoded: tkn, Sealed: data}
}
return &DelegationLoader{
@@ -106,7 +106,7 @@ func CidToName(id cid.Cid) string {
return cidToName[id]
}
func mustGetBundle(id cid.Cid) *delegation.Bundle {
func mustGetBundle(id cid.Cid) delegation.Bundle {
bundle, ok := GetDelegationLoader().bundles[id]
if !ok {
panic(delegation.ErrDelegationNotFound)

View File

@@ -195,7 +195,7 @@ var AllTokens = []*delegation.Token{
TokenErinFrank_ValidExamplePolicy,
}
var AllBundles = []*delegation.Bundle{
var AllBundles = []delegation.Bundle{
TokenAliceBobBundle,
TokenBobCarolBundle,
TokenCarolDanBundle,

View File

@@ -272,12 +272,14 @@ func ExampleFromSealed() {
// Policy (pol): [
// ["==", ".status", "draft"],
// ["all", ".reviewer",
// ["like", ".email", "*@example.com"]],
// ["like", ".email", "*@example.com"]
// ],
// ["any", ".tags",
// ["or", [
// ["==", ".", "news"],
// ["==", ".", "press"]]]
// ]
// ["==", ".", "press"]
// ]]
// ]
// ]
// Nonce (nonce): 000102030405060708090a0b
// Meta (meta): {}

View File

@@ -16,7 +16,7 @@ type Loader interface {
GetDelegation(cid cid.Cid) (*Token, error)
}
// Bundle carries together a decoded delegation with its Cid and raw signed data.
// Bundle carries together a decoded token with its Cid and raw signed data.
type Bundle struct {
Cid cid.Cid
Decoded *Token

View File

@@ -39,3 +39,10 @@ type Marshaller interface {
// ToDagJsonWriter is the same as ToDagJson, but it accepts an io.Writer.
ToDagJsonWriter(w io.Writer, privKey crypto.PrivKey) error
}
// Bundle carries together a decoded token with its Cid and raw signed data.
type Bundle struct {
Cid cid.Cid
Decoded Token
Sealed []byte
}

View File

@@ -59,6 +59,9 @@ type Token struct {
// New creates an invocation Token with the provided options.
//
// The given proofs MUST be ordered from the leaf (matching the invocation) to
// the root delegation.
//
// If no nonce is provided, a random 12-byte nonce is generated. Use the
// WithNonce or WithEmptyNonce options to specify provide your own nonce
// or to leave the nonce empty respectively.

View File

@@ -63,7 +63,7 @@ func (t *Token) verifyProofs(delegations []*delegation.Token) error {
sub = t.audience
}
// control from the invocation to the root
// control from the invocation to the root delegation
for i, dlgCid := range t.proof {
dlg := delegations[i]

View File

@@ -0,0 +1,10 @@
package invocation
import "github.com/ipfs/go-cid"
// Bundle carries together a decoded token with its Cid and raw signed data.
type Bundle struct {
Cid cid.Cid
Decoded *Token
Sealed []byte
}