Compare commits
9 Commits
feat/calcu
...
feat/deleg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79955057a3 | ||
|
|
59cebf8e74 | ||
|
|
952a6bb922 | ||
|
|
2089aa2a6a | ||
|
|
4a655506f9 | ||
|
|
93dd3ef719 | ||
|
|
6075c19957 | ||
|
|
6161f2e440 | ||
|
|
5202056cc7 |
@@ -116,3 +116,11 @@ func Parse(str string) (DID, error) {
|
||||
buf = append(buf, suffix...)
|
||||
return DID{str: string(buf), code: DIDCore}, nil
|
||||
}
|
||||
|
||||
func MustParse(str string) DID {
|
||||
did, err := Parse(str)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return did
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package did
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseDIDKey(t *testing.T) {
|
||||
@@ -15,6 +17,18 @@ func TestParseDIDKey(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMustParseDIDKey(t *testing.T) {
|
||||
str := "did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z"
|
||||
require.NotPanics(t, func() {
|
||||
d := MustParse(str)
|
||||
require.Equal(t, str, d.String())
|
||||
})
|
||||
str = "did:key:z7Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z"
|
||||
require.Panics(t, func() {
|
||||
MustParse(str)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDecodeDIDKey(t *testing.T) {
|
||||
str := "did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z"
|
||||
d0, err := Parse(str)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/capability/command"
|
||||
"github.com/ucan-wg/go-ucan/pkg/command"
|
||||
)
|
||||
|
||||
func TestTop(t *testing.T) {
|
||||
@@ -2,12 +2,16 @@ package meta
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
"github.com/ipld/go-ipld-prime/node/basicnode"
|
||||
)
|
||||
|
||||
var ErrUnsupported = errors.New("failure adding unsupported type to meta")
|
||||
|
||||
var ErrNotFound = errors.New("key-value not found in meta")
|
||||
|
||||
// Meta is a container for meta key-value pairs in a UCAN token.
|
||||
@@ -113,8 +117,20 @@ func (m *Meta) Add(key string, val any) error {
|
||||
case datamodel.Node:
|
||||
m.Values[key] = val
|
||||
default:
|
||||
panic("invalid value type")
|
||||
return fmt.Errorf("%w: %s", ErrUnsupported, fqtn(val))
|
||||
}
|
||||
m.Keys = append(m.Keys, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func fqtn(val any) string {
|
||||
var name string
|
||||
|
||||
t := reflect.TypeOf(val)
|
||||
for t.Kind() == reflect.Pointer {
|
||||
name += "*"
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
return name + t.PkgPath() + "." + t.Name()
|
||||
}
|
||||
|
||||
23
pkg/meta/meta_test.go
Normal file
23
pkg/meta/meta_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package meta_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/ucan-wg/go-ucan/pkg/meta"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestMeta_Add(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type Unsupported struct{}
|
||||
|
||||
t.Run("error if not primative or Node", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := (&meta.Meta{}).Add("invalid", &Unsupported{})
|
||||
require.ErrorIs(t, err, meta.ErrUnsupported)
|
||||
assert.ErrorContains(t, err, "*github.com/ucan-wg/go-ucan/pkg/meta_test.Unsupported")
|
||||
})
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/ipld/go-ipld-prime/must"
|
||||
"github.com/ipld/go-ipld-prime/node/basicnode"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/capability/policy/selector"
|
||||
"github.com/ucan-wg/go-ucan/pkg/policy/selector"
|
||||
)
|
||||
|
||||
func FromIPLD(node datamodel.Node) (Policy, error) {
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
"github.com/ipld/go-ipld-prime/must"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/capability/policy/selector"
|
||||
"github.com/ucan-wg/go-ucan/pkg/policy/selector"
|
||||
)
|
||||
|
||||
// Match determines if the IPLD node matches the policy document.
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"github.com/ipld/go-ipld-prime/node/basicnode"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/capability/policy/literal"
|
||||
"github.com/ucan-wg/go-ucan/capability/policy/selector"
|
||||
"github.com/ucan-wg/go-ucan/pkg/policy/literal"
|
||||
"github.com/ucan-wg/go-ucan/pkg/policy/selector"
|
||||
)
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
@@ -5,7 +5,7 @@ package policy
|
||||
import (
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/capability/policy/selector"
|
||||
"github.com/ucan-wg/go-ucan/pkg/policy/selector"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/capability/policy/selector"
|
||||
"github.com/ucan-wg/go-ucan/pkg/policy/selector"
|
||||
)
|
||||
|
||||
// TestSupported Forms runs tests against the Selector according to the
|
||||
@@ -18,10 +18,10 @@ import (
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/capability/command"
|
||||
"github.com/ucan-wg/go-ucan/capability/policy"
|
||||
"github.com/ucan-wg/go-ucan/did"
|
||||
"github.com/ucan-wg/go-ucan/pkg/command"
|
||||
"github.com/ucan-wg/go-ucan/pkg/meta"
|
||||
"github.com/ucan-wg/go-ucan/pkg/policy"
|
||||
)
|
||||
|
||||
// Token is an immutable type that holds the fields of a UCAN delegation.
|
||||
@@ -49,6 +49,10 @@ type Token struct {
|
||||
}
|
||||
|
||||
// New creates a validated Token from the provided parameters and options.
|
||||
//
|
||||
// When creating a delegated token, the Issuer's (iss) DID is assembed
|
||||
// using the public key associated with the private key sent as the first
|
||||
// parameter.
|
||||
func New(privKey crypto.PrivKey, aud did.DID, cmd command.Command, pol policy.Policy, opts ...Option) (*Token, error) {
|
||||
iss, err := did.FromPrivKey(privKey)
|
||||
if err != nil {
|
||||
@@ -86,6 +90,12 @@ func New(privKey crypto.PrivKey, aud did.DID, cmd command.Command, pol policy.Po
|
||||
return tkn, nil
|
||||
}
|
||||
|
||||
// Root creates a validated UCAN delegation Token from the provided
|
||||
// parameters and options.
|
||||
//
|
||||
// When creating a root token, both the Issuer's (iss) and Subject's
|
||||
// (sub) DIDs are assembled from the public key associated with the
|
||||
// private key passed as the first argument.
|
||||
func Root(privKey crypto.PrivKey, aud did.DID, cmd command.Command, pol policy.Policy, opts ...Option) (*Token, error) {
|
||||
sub, err := did.FromPrivKey(privKey)
|
||||
if err != nil {
|
||||
@@ -172,73 +182,6 @@ func (t *Token) validate() error {
|
||||
return errs
|
||||
}
|
||||
|
||||
// Option is a type that allows optional fields to be set during the
|
||||
// creation of a Token.
|
||||
type Option func(*Token) error
|
||||
|
||||
// WithExpiration set's the Token's optional "expiration" field to the
|
||||
// value of the provided time.Time.
|
||||
func WithExpiration(exp time.Time) Option {
|
||||
return func(t *Token) error {
|
||||
if exp.Before(time.Now()) {
|
||||
return fmt.Errorf("a Token's expiration should be set to a time in the future: %s", exp.String())
|
||||
}
|
||||
|
||||
t.expiration = &exp
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithMeta adds a key/value pair in the "meta" field.
|
||||
//
|
||||
// WithMeta can be used multiple times in the same call.
|
||||
// Accepted types for the value are: bool, string, int, int32, int64, []byte,
|
||||
// and ipld.Node.
|
||||
func WithMeta(key string, val any) Option {
|
||||
return func(t *Token) error {
|
||||
return t.meta.Add(key, val)
|
||||
}
|
||||
}
|
||||
|
||||
// WithNotBefore set's the Token's optional "notBefore" field to the value
|
||||
// of the provided time.Time.
|
||||
func WithNotBefore(nbf time.Time) Option {
|
||||
return func(t *Token) error {
|
||||
if nbf.Before(time.Now()) {
|
||||
return fmt.Errorf("a Token's \"not before\" field should be set to a time in the future: %s", nbf.String())
|
||||
}
|
||||
|
||||
t.notBefore = &nbf
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithSubject sets the Tokens's optional "subject" field to the value of
|
||||
// provided did.DID.
|
||||
//
|
||||
// This Option should only be used with the New constructor - since
|
||||
// Subject is a required parameter when creating a Token via the Root
|
||||
// constructor, any value provided via this Option will be silently
|
||||
// overwritten.
|
||||
func WithSubject(sub did.DID) Option {
|
||||
return func(t *Token) error {
|
||||
t.subject = sub
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithNonce sets the Token's nonce with the given value.
|
||||
// If this option is not used, a random 12-byte nonce is generated for this required field.
|
||||
func WithNonce(nonce []byte) Option {
|
||||
return func(t *Token) error {
|
||||
t.nonce = nonce
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// tokenFromModel build a decoded view of the raw IPLD data.
|
||||
// This function also serves as validation.
|
||||
func tokenFromModel(m tokenPayloadModel) (*Token, error) {
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"gotest.tools/v3/golden"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/capability/command"
|
||||
"github.com/ucan-wg/go-ucan/capability/policy"
|
||||
"github.com/ucan-wg/go-ucan/delegation"
|
||||
"github.com/ucan-wg/go-ucan/did"
|
||||
"github.com/ucan-wg/go-ucan/pkg/command"
|
||||
"github.com/ucan-wg/go-ucan/pkg/policy"
|
||||
"github.com/ucan-wg/go-ucan/tokens/delegation"
|
||||
)
|
||||
|
||||
const (
|
||||
313
tokens/delegation/examples_test.go
Normal file
313
tokens/delegation/examples_test.go
Normal file
@@ -0,0 +1,313 @@
|
||||
package delegation_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
"github.com/ipld/go-ipld-prime/codec/dagcbor"
|
||||
"github.com/ipld/go-ipld-prime/codec/dagjson"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/ucan-wg/go-ucan/did"
|
||||
"github.com/ucan-wg/go-ucan/pkg/command"
|
||||
"github.com/ucan-wg/go-ucan/pkg/policy"
|
||||
"github.com/ucan-wg/go-ucan/tokens/delegation"
|
||||
"github.com/ucan-wg/go-ucan/tokens/internal/envelope"
|
||||
)
|
||||
|
||||
// The following example shows how to create a delegation.Token with
|
||||
// distinct DIDs for issuer (iss), audience (aud) and subject (sub).
|
||||
func ExampleNew() {
|
||||
issuerPrivKey := examplePrivKey(issuerPrivKeyCfg)
|
||||
audienceDID := exampleDID(AudienceDID)
|
||||
command := exampleCommand(subJectCmd)
|
||||
policy := examplePolicy(subjectPol)
|
||||
subjectDID := exampleDID(subjectDID)
|
||||
|
||||
// Don't do this in your code - a nonce should be a cryptographically
|
||||
// strong random slice of bytes to ensure the integrity of your private
|
||||
// key. For this example, a fixed nonce is required to obtain the fixed
|
||||
// printed output (below). If unsure of what value to supply for the
|
||||
// nonce, don't pass the WithNonce option and one will be generated
|
||||
// when the token is created.
|
||||
nonce := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b}
|
||||
|
||||
tkn, err := delegation.New(
|
||||
issuerPrivKey,
|
||||
audienceDID,
|
||||
command,
|
||||
policy,
|
||||
delegation.WithSubject(subjectDID),
|
||||
delegation.WithNonce(nonce),
|
||||
)
|
||||
printThenPanicOnErr(err)
|
||||
data, id, err := tkn.ToSealed(issuerPrivKey)
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
printCIDAndSealed(id, data)
|
||||
|
||||
//Output:
|
||||
//CID (base58BTC): zdpuAw26pFuvZa2Z9YAtpZZnWN6VmnRFr7Z8LVY5c7RVWoxGY
|
||||
//DAG-CBOR (base64) out: glhAmnAkgfjAx4SA5pzJmtaHRJtTGNpF1y6oqb4yhGoM2H2EUGbBYT4rVDjMKBgCjhdGHjipm00L8iR5SsQh3sIEBaJhaEQ07QFxc3VjYW4vZGxnQDEuMC4wLXJjLjGoY2F1ZHg4ZGlkOmtleTp6Nk1rcTVZbWJKY1RyUEV4TkRpMjZpbXJUQ3BLaGVwakJGQlNIcXJCRE4yQXJQa3ZjY21kaC9mb28vYmFyY2V4cPZjaXNzeDhkaWQ6a2V5Ono2TWtwem4ybjNaR1QyVmFxTUdTUUMzdHptelY0VFM5UzcxaUZzRFhFMVdub05IMmNwb2yDg2I9PWcuc3RhdHVzZWRyYWZ0g2NhbGxpLnJldmlld2Vyg2RsaWtlZi5lbWFpbG0qQGV4YW1wbGUuY29tg2NhbnllLnRhZ3OCYm9ygoNiPT1hLmRuZXdzg2I9PWEuZXByZXNzY3N1Yng4ZGlkOmtleTp6Nk1rdEExdUJkQ3BxNHVKQnFFOWpqTWlMeXhaQmc5YTZ4Z1BQS0pqTXFzczZaYzJkbWV0YaBlbm9uY2VMAAECAwQFBgcICQoL
|
||||
//Converted to DAG-JSON out:
|
||||
//[
|
||||
// {
|
||||
// "/": {
|
||||
// "bytes": "mnAkgfjAx4SA5pzJmtaHRJtTGNpF1y6oqb4yhGoM2H2EUGbBYT4rVDjMKBgCjhdGHjipm00L8iR5SsQh3sIEBQ"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "h": {
|
||||
// "/": {
|
||||
// "bytes": "NO0BcQ"
|
||||
// }
|
||||
// },
|
||||
// "ucan/dlg@1.0.0-rc.1": {
|
||||
// "aud": "did:key:z6Mkq5YmbJcTrPExNDi26imrTCpKhepjBFBSHqrBDN2ArPkv",
|
||||
// "cmd": "/foo/bar",
|
||||
// "exp": null,
|
||||
// "iss": "did:key:z6Mkpzn2n3ZGT2VaqMGSQC3tzmzV4TS9S71iFsDXE1WnoNH2",
|
||||
// "meta": {},
|
||||
// "nonce": {
|
||||
// "/": {
|
||||
// "bytes": "AAECAwQFBgcICQoL"
|
||||
// }
|
||||
// },
|
||||
// "pol": [
|
||||
// [
|
||||
// "==",
|
||||
// ".status",
|
||||
// "draft"
|
||||
// ],
|
||||
// [
|
||||
// "all",
|
||||
// ".reviewer",
|
||||
// [
|
||||
// "like",
|
||||
// ".email",
|
||||
// "*@example.com"
|
||||
// ]
|
||||
// ],
|
||||
// [
|
||||
// "any",
|
||||
// ".tags",
|
||||
// [
|
||||
// "or",
|
||||
// [
|
||||
// [
|
||||
// "==",
|
||||
// ".",
|
||||
// "news"
|
||||
// ],
|
||||
// [
|
||||
// "==",
|
||||
// ".",
|
||||
// "press"
|
||||
// ]
|
||||
// ]
|
||||
// ]
|
||||
// ]
|
||||
// ],
|
||||
// "sub": "did:key:z6MktA1uBdCpq4uJBqE9jjMiLyxZBg9a6xgPPKJjMqss6Zc2"
|
||||
// }
|
||||
// }
|
||||
//]
|
||||
}
|
||||
|
||||
// The following example shows how to create a UCAN root delegation.Token
|
||||
// - a delegation.Token with the subject (sub) set to the value of issuer
|
||||
// (iss).
|
||||
func ExampleRoot() {
|
||||
issuerPrivKey := examplePrivKey(issuerPrivKeyCfg)
|
||||
audienceDID := exampleDID(AudienceDID)
|
||||
command := exampleCommand(subJectCmd)
|
||||
policy := examplePolicy(subjectPol)
|
||||
|
||||
// Don't do this in your code - a nonce should be a cryptographically
|
||||
// strong random slice of bytes to ensure the integrity of your private
|
||||
// key. For this example, a fixed nonce is required to obtain the fixed
|
||||
// printed output (below). If unsure of what value to supply for the
|
||||
// nonce, don't pass the WithNonce option and one will be generated
|
||||
// when the token is created.
|
||||
nonce := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b}
|
||||
|
||||
tkn, err := delegation.Root(
|
||||
issuerPrivKey,
|
||||
audienceDID,
|
||||
command,
|
||||
policy,
|
||||
delegation.WithNonce(nonce),
|
||||
)
|
||||
printThenPanicOnErr(err)
|
||||
data, id, err := tkn.ToSealed(issuerPrivKey)
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
printCIDAndSealed(id, data)
|
||||
|
||||
//Output:
|
||||
//CID (base58BTC): zdpuAnbsR3e6DK8hBk5WA7KwbHYN6CKY4a3Bv1GNehvFYShQ8
|
||||
//DAG-CBOR (base64) out: glhA67ASBczF/wlIP0ESENn+4ZNQKukjcTNz+fo7K2tYa6OUm0rWICDJJkDWm7lJeQt+KvSA+Y4ctHTQbAr3Lr7mDqJhaEQ07QFxc3VjYW4vZGxnQDEuMC4wLXJjLjGoY2F1ZHg4ZGlkOmtleTp6Nk1rcTVZbWJKY1RyUEV4TkRpMjZpbXJUQ3BLaGVwakJGQlNIcXJCRE4yQXJQa3ZjY21kaC9mb28vYmFyY2V4cPZjaXNzeDhkaWQ6a2V5Ono2TWtwem4ybjNaR1QyVmFxTUdTUUMzdHptelY0VFM5UzcxaUZzRFhFMVdub05IMmNwb2yDg2I9PWcuc3RhdHVzZWRyYWZ0g2NhbGxpLnJldmlld2Vyg2RsaWtlZi5lbWFpbG0qQGV4YW1wbGUuY29tg2NhbnllLnRhZ3OCYm9ygoNiPT1hLmRuZXdzg2I9PWEuZXByZXNzY3N1Yng4ZGlkOmtleTp6Nk1rcHpuMm4zWkdUMlZhcU1HU1FDM3R6bXpWNFRTOVM3MWlGc0RYRTFXbm9OSDJkbWV0YaBlbm9uY2VMAAECAwQFBgcICQoL
|
||||
//Converted to DAG-JSON out:
|
||||
//[
|
||||
// {
|
||||
// "/": {
|
||||
// "bytes": "67ASBczF/wlIP0ESENn+4ZNQKukjcTNz+fo7K2tYa6OUm0rWICDJJkDWm7lJeQt+KvSA+Y4ctHTQbAr3Lr7mDg"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "h": {
|
||||
// "/": {
|
||||
// "bytes": "NO0BcQ"
|
||||
// }
|
||||
// },
|
||||
// "ucan/dlg@1.0.0-rc.1": {
|
||||
// "aud": "did:key:z6Mkq5YmbJcTrPExNDi26imrTCpKhepjBFBSHqrBDN2ArPkv",
|
||||
// "cmd": "/foo/bar",
|
||||
// "exp": null,
|
||||
// "iss": "did:key:z6Mkpzn2n3ZGT2VaqMGSQC3tzmzV4TS9S71iFsDXE1WnoNH2",
|
||||
// "meta": {},
|
||||
// "nonce": {
|
||||
// "/": {
|
||||
// "bytes": "AAECAwQFBgcICQoL"
|
||||
// }
|
||||
// },
|
||||
// "pol": [
|
||||
// [
|
||||
// "==",
|
||||
// ".status",
|
||||
// "draft"
|
||||
// ],
|
||||
// [
|
||||
// "all",
|
||||
// ".reviewer",
|
||||
// [
|
||||
// "like",
|
||||
// ".email",
|
||||
// "*@example.com"
|
||||
// ]
|
||||
// ],
|
||||
// [
|
||||
// "any",
|
||||
// ".tags",
|
||||
// [
|
||||
// "or",
|
||||
// [
|
||||
// [
|
||||
// "==",
|
||||
// ".",
|
||||
// "news"
|
||||
// ],
|
||||
// [
|
||||
// "==",
|
||||
// ".",
|
||||
// "press"
|
||||
// ]
|
||||
// ]
|
||||
// ]
|
||||
// ]
|
||||
// ],
|
||||
// "sub": "did:key:z6Mkpzn2n3ZGT2VaqMGSQC3tzmzV4TS9S71iFsDXE1WnoNH2"
|
||||
// }
|
||||
// }
|
||||
//]
|
||||
}
|
||||
|
||||
// The following example demonstrates how to get a delegation.Token from
|
||||
// a DAG-CBOR []byte.
|
||||
func ExampleToken_FromSealed() {
|
||||
cborBytes := exampleCBORData()
|
||||
fmt.Println("DAG-CBOR (base64) in:", base64.StdEncoding.EncodeToString(cborBytes))
|
||||
|
||||
tkn, err := delegation.FromSealed(cborBytes)
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
fmt.Println("CID (base58BTC):", envelope.CIDToBase58BTC(tkn.CID()))
|
||||
fmt.Println("Issuer (iss):", tkn.Issuer().String())
|
||||
fmt.Println("Audience (aud):", tkn.Audience().String())
|
||||
fmt.Println("Subject (sub):", tkn.Subject().String())
|
||||
fmt.Println("Command (cmd):", tkn.Command().String())
|
||||
fmt.Println("Policy (pol): TODO")
|
||||
fmt.Println("Nonce (nonce):", hex.EncodeToString(tkn.Nonce()))
|
||||
fmt.Println("Meta (meta): TODO")
|
||||
fmt.Println("NotBefore (nbf):", tkn.NotBefore())
|
||||
fmt.Println("Expiration (exp):", tkn.Expiration())
|
||||
|
||||
//Output:
|
||||
//DAG-CBOR (base64) in: glhAmnAkgfjAx4SA5pzJmtaHRJtTGNpF1y6oqb4yhGoM2H2EUGbBYT4rVDjMKBgCjhdGHjipm00L8iR5SsQh3sIEBaJhaEQ07QFxc3VjYW4vZGxnQDEuMC4wLXJjLjGoY2F1ZHg4ZGlkOmtleTp6Nk1rcTVZbWJKY1RyUEV4TkRpMjZpbXJUQ3BLaGVwakJGQlNIcXJCRE4yQXJQa3ZjY21kaC9mb28vYmFyY2V4cPZjaXNzeDhkaWQ6a2V5Ono2TWtwem4ybjNaR1QyVmFxTUdTUUMzdHptelY0VFM5UzcxaUZzRFhFMVdub05IMmNwb2yDg2I9PWcuc3RhdHVzZWRyYWZ0g2NhbGxpLnJldmlld2Vyg2RsaWtlZi5lbWFpbG0qQGV4YW1wbGUuY29tg2NhbnllLnRhZ3OCYm9ygoNiPT1hLmRuZXdzg2I9PWEuZXByZXNzY3N1Yng4ZGlkOmtleTp6Nk1rdEExdUJkQ3BxNHVKQnFFOWpqTWlMeXhaQmc5YTZ4Z1BQS0pqTXFzczZaYzJkbWV0YaBlbm9uY2VMAAECAwQFBgcICQoL
|
||||
//CID (base58BTC): zdpuAw26pFuvZa2Z9YAtpZZnWN6VmnRFr7Z8LVY5c7RVWoxGY
|
||||
//Issuer (iss): did:key:z6Mkpzn2n3ZGT2VaqMGSQC3tzmzV4TS9S71iFsDXE1WnoNH2
|
||||
//Audience (aud): did:key:z6Mkq5YmbJcTrPExNDi26imrTCpKhepjBFBSHqrBDN2ArPkv
|
||||
//Subject (sub): did:key:z6MktA1uBdCpq4uJBqE9jjMiLyxZBg9a6xgPPKJjMqss6Zc2
|
||||
//Command (cmd): /foo/bar
|
||||
//Policy (pol): TODO
|
||||
//Nonce (nonce): 000102030405060708090a0b
|
||||
//Meta (meta): TODO
|
||||
//NotBefore (nbf): <nil>
|
||||
//Expiration (exp): <nil>
|
||||
}
|
||||
|
||||
func exampleCBORData() []byte {
|
||||
data, err := base64.StdEncoding.DecodeString("glhAmnAkgfjAx4SA5pzJmtaHRJtTGNpF1y6oqb4yhGoM2H2EUGbBYT4rVDjMKBgCjhdGHjipm00L8iR5SsQh3sIEBaJhaEQ07QFxc3VjYW4vZGxnQDEuMC4wLXJjLjGoY2F1ZHg4ZGlkOmtleTp6Nk1rcTVZbWJKY1RyUEV4TkRpMjZpbXJUQ3BLaGVwakJGQlNIcXJCRE4yQXJQa3ZjY21kaC9mb28vYmFyY2V4cPZjaXNzeDhkaWQ6a2V5Ono2TWtwem4ybjNaR1QyVmFxTUdTUUMzdHptelY0VFM5UzcxaUZzRFhFMVdub05IMmNwb2yDg2I9PWcuc3RhdHVzZWRyYWZ0g2NhbGxpLnJldmlld2Vyg2RsaWtlZi5lbWFpbG0qQGV4YW1wbGUuY29tg2NhbnllLnRhZ3OCYm9ygoNiPT1hLmRuZXdzg2I9PWEuZXByZXNzY3N1Yng4ZGlkOmtleTp6Nk1rdEExdUJkQ3BxNHVKQnFFOWpqTWlMeXhaQmc5YTZ4Z1BQS0pqTXFzczZaYzJkbWV0YaBlbm9uY2VMAAECAwQFBgcICQoL")
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func exampleDID(didStr string) did.DID {
|
||||
id, err := did.Parse(didStr)
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
func exampleCommand(cmdStr string) command.Command {
|
||||
cmd, err := command.Parse(cmdStr)
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func examplePolicy(policyJSON string) policy.Policy {
|
||||
pol, err := policy.FromDagJson(policyJSON)
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
return pol
|
||||
}
|
||||
|
||||
func examplePrivKey(privKeyCfg string) crypto.PrivKey {
|
||||
privKeyMar, err := crypto.ConfigDecodeKey(privKeyCfg)
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
privKey, err := crypto.UnmarshalPrivateKey(privKeyMar)
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
return privKey
|
||||
}
|
||||
|
||||
func printCIDAndSealed(id cid.Cid, data []byte) {
|
||||
fmt.Println("CID (base58BTC):", envelope.CIDToBase58BTC(id))
|
||||
fmt.Println("DAG-CBOR (base64) out:", base64.StdEncoding.EncodeToString(data))
|
||||
fmt.Println("Converted to DAG-JSON out:")
|
||||
|
||||
node, err := ipld.Decode(data, dagcbor.Decode)
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
rawJSON, err := ipld.Encode(node, dagjson.Encode)
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
prettyJSON := &bytes.Buffer{}
|
||||
err = json.Indent(prettyJSON, rawJSON, "", "\t")
|
||||
printThenPanicOnErr(err)
|
||||
|
||||
fmt.Println(prettyJSON.String())
|
||||
}
|
||||
|
||||
func printThenPanicOnErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/did"
|
||||
"github.com/ucan-wg/go-ucan/internal/envelope"
|
||||
"github.com/ucan-wg/go-ucan/tokens/internal/envelope"
|
||||
)
|
||||
|
||||
// ToSealed wraps the delegation token in an envelope, generates the
|
||||
72
tokens/delegation/options.go
Normal file
72
tokens/delegation/options.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package delegation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/did"
|
||||
)
|
||||
|
||||
// Option is a type that allows optional fields to be set during the
|
||||
// creation of a Token.
|
||||
type Option func(*Token) error
|
||||
|
||||
// WithExpiration set's the Token's optional "expiration" field to the
|
||||
// value of the provided time.Time.
|
||||
func WithExpiration(exp time.Time) Option {
|
||||
return func(t *Token) error {
|
||||
if exp.Before(time.Now()) {
|
||||
return fmt.Errorf("a Token's expiration should be set to a time in the future: %s", exp.String())
|
||||
}
|
||||
|
||||
t.expiration = &exp
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithMeta adds a key/value pair in the "meta" field.
|
||||
//
|
||||
// WithMeta can be used multiple times in the same call.
|
||||
// Accepted types for the value are: bool, string, int, int32, int64, []byte,
|
||||
// and ipld.Node.
|
||||
func WithMeta(key string, val any) Option {
|
||||
return func(t *Token) error {
|
||||
return t.meta.Add(key, val)
|
||||
}
|
||||
}
|
||||
|
||||
// WithNotBefore set's the Token's optional "notBefore" field to the value
|
||||
// of the provided time.Time.
|
||||
func WithNotBefore(nbf time.Time) Option {
|
||||
return func(t *Token) error {
|
||||
if nbf.Before(time.Now()) {
|
||||
return fmt.Errorf("a Token's \"not before\" field should be set to a time in the future: %s", nbf.String())
|
||||
}
|
||||
|
||||
t.notBefore = &nbf
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithSubject sets the Tokens's optional "subject" field to the value of
|
||||
// provided did.DID.
|
||||
//
|
||||
// This Option should only be used with the New constructor - since
|
||||
// Subject is a required parameter when creating a Token via the Root
|
||||
// constructor, any value provided via this Option will be silently
|
||||
// overwritten.
|
||||
func WithSubject(sub did.DID) Option {
|
||||
return func(t *Token) error {
|
||||
t.subject = sub
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithNonce sets the Token's nonce with the given value.
|
||||
// If this option is not used, a random 12-byte nonce is generated for this required field.
|
||||
func WithNonce(nonce []byte) Option {
|
||||
return func(t *Token) error {
|
||||
t.nonce = nonce
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"github.com/ipld/go-ipld-prime/node/bindnode"
|
||||
"github.com/ipld/go-ipld-prime/schema"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/internal/envelope"
|
||||
"github.com/ucan-wg/go-ucan/pkg/meta"
|
||||
"github.com/ucan-wg/go-ucan/tokens/internal/envelope"
|
||||
)
|
||||
|
||||
// [Tag] is the string used as a key within the SigPayload that identifies
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"gotest.tools/v3/golden"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/delegation"
|
||||
"github.com/ucan-wg/go-ucan/internal/envelope"
|
||||
"github.com/ucan-wg/go-ucan/tokens/delegation"
|
||||
"github.com/ucan-wg/go-ucan/tokens/internal/envelope"
|
||||
)
|
||||
|
||||
//go:embed delegation.ipldsch
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"gotest.tools/v3/golden"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/internal/envelope"
|
||||
"github.com/ucan-wg/go-ucan/tokens/internal/envelope"
|
||||
)
|
||||
|
||||
func TestCidFromBytes(t *testing.T) {
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/ipld/go-ipld-prime/schema"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/ucan-wg/go-ucan/internal/envelope"
|
||||
"github.com/ucan-wg/go-ucan/tokens/internal/envelope"
|
||||
"gotest.tools/v3/golden"
|
||||
)
|
||||
|
||||
@@ -41,7 +41,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/did"
|
||||
"github.com/ucan-wg/go-ucan/internal/varsig"
|
||||
"github.com/ucan-wg/go-ucan/tokens/internal/varsig"
|
||||
)
|
||||
|
||||
const varsigHeaderKey = "h"
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/ucan-wg/go-ucan/internal/envelope"
|
||||
"github.com/ucan-wg/go-ucan/tokens/internal/envelope"
|
||||
"gotest.tools/v3/golden"
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/crypto/pb"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/ucan-wg/go-ucan/internal/varsig"
|
||||
"github.com/ucan-wg/go-ucan/tokens/internal/varsig"
|
||||
)
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
Reference in New Issue
Block a user