Compare commits
24 Commits
cont-namin
...
v1.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a82bce556f | ||
|
|
a54d66afe5 | ||
|
|
14a57d7391 | ||
|
|
68469db91a | ||
|
|
cc1d68be0c | ||
|
|
6d3846ac62 | ||
|
|
6aa33b1547 | ||
|
|
9589cc8b44 | ||
|
|
879c0ab03b | ||
|
|
fe14765c8d | ||
|
|
1b28cb49bf | ||
|
|
e1fc838caf | ||
|
|
f29b9e94fc | ||
|
|
506ed21b94 | ||
|
|
126177b9e5 | ||
|
|
2bddab8b0c | ||
|
|
45ead12131 | ||
|
|
9d5e170409 | ||
|
|
9d047f038d | ||
|
|
4c5afcb084 | ||
|
|
e218b49577 | ||
|
|
4c81ac778e | ||
|
|
7ae65e7c8e | ||
|
|
7f9cb6426c |
@@ -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
10
go.mod
@@ -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
29
go.sum
@@ -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=
|
||||
|
||||
21
pkg/container/containertest/containertest.go
Normal file
21
pkg/container/containertest/containertest.go
Normal 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
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"}`))
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"]
|
||||
// ]]
|
||||
// ]
|
||||
// ]
|
||||
}
|
||||
|
||||
|
||||
@@ -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().
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -195,7 +195,7 @@ var AllTokens = []*delegation.Token{
|
||||
TokenErinFrank_ValidExamplePolicy,
|
||||
}
|
||||
|
||||
var AllBundles = []*delegation.Bundle{
|
||||
var AllBundles = []delegation.Bundle{
|
||||
TokenAliceBobBundle,
|
||||
TokenBobCarolBundle,
|
||||
TokenCarolDanBundle,
|
||||
|
||||
@@ -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): {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
10
token/invocation/utilities.go
Normal file
10
token/invocation/utilities.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user