Documentation ¶
Overview ¶
Package delegation implements the UCAN delegation specification with an immutable Token type as well as methods to convert the Token to and from the envelope-enclosed, signed and DAG-CBOR-encoded form that should most commonly be used for transport and storage.
Index ¶
- Constants
- Variables
- type Bundle
- type Loader
- type Option
- func WithEncryptedMetaBytes(key string, val, encryptionKey []byte) Option
- func WithEncryptedMetaString(key, val string, encryptionKey []byte) Option
- func WithExpiration(exp time.Time) Option
- func WithExpirationIn(exp time.Duration) Option
- func WithMeta(key string, val any) Option
- func WithNonce(nonce []byte) Option
- func WithNotBefore(nbf time.Time) Option
- func WithNotBeforeIn(nbf time.Duration) Option
- type Token
- func Decode(b []byte, decFn codec.Decoder) (*Token, error)
- func DecodeReader(r io.Reader, decFn codec.Decoder) (*Token, error)
- func FromDagCbor(data []byte) (*Token, error)
- func FromDagCborReader(r io.Reader) (*Token, error)
- func FromDagJson(data []byte) (*Token, error)
- func FromDagJsonReader(r io.Reader) (*Token, error)
- func FromIPLD(node datamodel.Node) (*Token, error)
- func FromSealed(data []byte) (*Token, cid.Cid, error)
- func FromSealedReader(r io.Reader) (*Token, cid.Cid, error)
- func New(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, sub did.DID, ...) (*Token, error)
- func Powerline(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, ...) (*Token, error)
- func Root(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, ...) (*Token, error)
- func (t *Token) Audience() did.DID
- func (t *Token) Command() command.Command
- func (t *Token) Encode(privKey crypto.PrivKey, encFn codec.Encoder) ([]byte, error)
- func (t *Token) EncodeWriter(w io.Writer, privKey crypto.PrivKey, encFn codec.Encoder) error
- func (t *Token) Expiration() *time.Time
- func (t *Token) IsValidAt(ti time.Time) bool
- func (t *Token) IsValidNow() bool
- func (t *Token) Issuer() did.DID
- func (t *Token) Meta() meta.ReadOnly
- func (t *Token) Nonce() []byte
- func (t *Token) NotBefore() *time.Time
- func (t *Token) Policy() policy.Policy
- func (t *Token) String() string
- func (t *Token) Subject() did.DID
- func (t *Token) ToDagCbor(privKey crypto.PrivKey) ([]byte, error)
- func (t *Token) ToDagCborWriter(w io.Writer, privKey crypto.PrivKey) error
- func (t *Token) ToDagJson(privKey crypto.PrivKey) ([]byte, error)
- func (t *Token) ToDagJsonWriter(w io.Writer, privKey crypto.PrivKey) error
- func (t *Token) ToSealed(privKey crypto.PrivKey) ([]byte, cid.Cid, error)
- func (t *Token) ToSealedWriter(w io.Writer, privKey crypto.PrivKey) (cid.Cid, error)
Examples ¶
Constants ¶
const Tag = "ucan/dlg@1.0.0-rc.1"
Tag is the string used as a key within the SigPayload that identifies that the TokenPayload is a delegation.
Variables ¶
var ErrDelegationNotFound = fmt.Errorf("delegation not found")
ErrDelegationNotFound is returned if a delegation token is not found
Functions ¶
This section is empty.
Types ¶
type Loader ¶
type Loader interface { // GetDelegation returns the delegation.Token matching the given CID. // If not found, ErrDelegationNotFound is returned. GetDelegation(cid cid.Cid) (*Token, error) }
Loader is a delegation token loader.
type Option ¶
Option is a type that allows optional fields to be set during the creation of a Token.
func WithEncryptedMetaBytes ¶
WithEncryptedMetaBytes adds a key/value pair in the "meta" field. The []byte value is encrypted with the given key. The ciphertext will be 40 bytes larger than the plaintext due to encryption overhead.
func WithEncryptedMetaString ¶
WithEncryptedMetaString adds a key/value pair in the "meta" field. The string value is encrypted with the given key. The ciphertext will be 40 bytes larger than the plaintext due to encryption overhead.
func WithExpiration ¶
WithExpiration set's the Token's optional "expiration" field to the value of the provided time.Time.
func WithExpirationIn ¶
WithExpirationIn set's the Token's optional "expiration" field to Now() plus the given duration.
func WithMeta ¶
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 WithNonce ¶
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 WithNotBefore ¶
WithNotBefore set's the Token's optional "notBefore" field to the value of the provided time.Time.
func WithNotBeforeIn ¶
WithNotBeforeIn set's the Token's optional "notBefore" field to the value of the provided time.Time.
type Token ¶
type Token struct {
// contains filtered or unexported fields
}
Token is an immutable type that holds the fields of a UCAN delegation.
func Decode ¶
Decode unmarshals the input data using the format specified by the provided codec.Decoder into a Token.
An error is returned if the conversion fails, or if the resulting Token is invalid.
func DecodeReader ¶
DecodeReader is the same as Decode, but accept an io.Reader.
func FromDagCbor ¶
FromDagCbor unmarshals the input data into a Token.
An error is returned if the conversion fails, or if the resulting Token is invalid.
func FromDagCborReader ¶
FromDagCborReader is the same as FromDagCbor, but accept an io.Reader.
func FromDagJson ¶
FromDagJson unmarshals the input data into a Token.
An error is returned if the conversion fails, or if the resulting Token is invalid.
func FromDagJsonReader ¶
FromDagJsonReader is the same as FromDagJson, but accept an io.Reader.
func FromSealed ¶
FromSealed decodes the provided binary data from the DAG-CBOR format, verifies that the envelope's signature is correct based on the public key taken from the issuer (iss) field and calculates the CID of the incoming data.
Example ¶
The following example demonstrates how to get a delegation.Token from a DAG-CBOR []byte.
package main import ( "encoding/base64" "encoding/hex" "fmt" "github.com/ucan-wg/go-ucan/token/delegation" "github.com/ucan-wg/go-ucan/token/internal/envelope" ) func main() { const cborBase64 = "glhAmnAkgfjAx4SA5pzJmtaHRJtTGNpF1y6oqb4yhGoM2H2EUGbBYT4rVDjMKBgCjhdGHjipm00L8iR5SsQh3sIEBaJhaEQ07QFxc3VjYW4vZGxnQDEuMC4wLXJjLjGoY2F1ZHg4ZGlkOmtleTp6Nk1rcTVZbWJKY1RyUEV4TkRpMjZpbXJUQ3BLaGVwakJGQlNIcXJCRE4yQXJQa3ZjY21kaC9mb28vYmFyY2V4cPZjaXNzeDhkaWQ6a2V5Ono2TWtwem4ybjNaR1QyVmFxTUdTUUMzdHptelY0VFM5UzcxaUZzRFhFMVdub05IMmNwb2yDg2I9PWcuc3RhdHVzZWRyYWZ0g2NhbGxpLnJldmlld2Vyg2RsaWtlZi5lbWFpbG0qQGV4YW1wbGUuY29tg2NhbnllLnRhZ3OCYm9ygoNiPT1hLmRuZXdzg2I9PWEuZXByZXNzY3N1Yng4ZGlkOmtleTp6Nk1rdEExdUJkQ3BxNHVKQnFFOWpqTWlMeXhaQmc5YTZ4Z1BQS0pqTXFzczZaYzJkbWV0YaBlbm9uY2VMAAECAwQFBgcICQoL" cborBytes, err := base64.StdEncoding.DecodeString(cborBase64) printThenPanicOnErr(err) tkn, c, err := delegation.FromSealed(cborBytes) printThenPanicOnErr(err) fmt.Println("CID (base58BTC):", envelope.CIDToBase58BTC(c)) 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):", tkn.Policy().String()) fmt.Println("Nonce (nonce):", hex.EncodeToString(tkn.Nonce())) fmt.Println("Meta (meta):", tkn.Meta().String()) fmt.Println("NotBefore (nbf):", tkn.NotBefore()) fmt.Println("Expiration (exp):", tkn.Expiration()) } func printThenPanicOnErr(err error) { if err != nil { panic(err) } }
Output: CID (base58BTC): zdpuAw26pFuvZa2Z9YAtpZZnWN6VmnRFr7Z8LVY5c7RVWoxGY Issuer (iss): did:key:z6Mkpzn2n3ZGT2VaqMGSQC3tzmzV4TS9S71iFsDXE1WnoNH2 Audience (aud): did:key:z6Mkq5YmbJcTrPExNDi26imrTCpKhepjBFBSHqrBDN2ArPkv Subject (sub): did:key:z6MktA1uBdCpq4uJBqE9jjMiLyxZBg9a6xgPPKJjMqss6Zc2 Command (cmd): /foo/bar Policy (pol): [ ["==", ".status", "draft"], ["all", ".reviewer", ["like", ".email", "*@example.com"] ], ["any", ".tags", ["or", [ ["==", ".", "news"], ["==", ".", "press"] ]] ] ] Nonce (nonce): 000102030405060708090a0b Meta (meta): {} NotBefore (nbf): <nil> Expiration (exp): <nil>
func FromSealedReader ¶
FromSealedReader is the same as Unseal but accepts an io.Reader.
func New ¶
func New(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, sub did.DID, opts ...Option) (*Token, error)
New creates a validated delegation Token from the provided parameters and options. This is typically used to delegate a given power to another agent.
You can read it as "(issuer) allows (audience) to perform (cmd+pol) on (subject)".
Example ¶
The following example shows how to create a delegation.Token with distinct DIDs for issuer (iss), audience (aud) and subject (sub).
fmt.Println("issDid:", didtest.PersonaBob.DID().String()) // The command defines the shape of the arguments that will be evaluated against the policy cmd := command.MustParse("/foo/bar") // The policy defines what is allowed to do. pol := policy.MustConstruct( policy.Equal(".status", literal.String("draft")), policy.All(".reviewer", policy.Like(".email", "*@example.com"), ), policy.Any(".tags", policy.Or( policy.Equal(".", literal.String("news")), policy.Equal(".", literal.String("press")), )), ) tkn, err := delegation.New(didtest.PersonaBob.DID(), didtest.PersonaCarol.DID(), cmd, pol, didtest.PersonaAlice.DID(), delegation.WithExpirationIn(time.Hour), delegation.WithNotBeforeIn(time.Minute), delegation.WithMeta("foo", "bar"), delegation.WithMeta("baz", 123), ) printThenPanicOnErr(err) // "Seal", meaning encode and wrap into a signed envelope. data, id, err := tkn.ToSealed(didtest.PersonaBob.PrivKey()) printThenPanicOnErr(err) printCIDAndSealed(id, data) // Example output: // // issDid: did:key:z6MkvJPmEZZYbgiw1ouT1oouTsTFBHJSts9ophVsNgcRmYxU // // CID (base58BTC): zdpuAsqfZkgg2jgZyob23sq1J9xwtf9PHgt1PsskVCMq7Vvxk // // DAG-CBOR (base64) out: lhAOnjc0bPptlI5MxRBrIK3YmAP1CxKfXOPkz6MHt/UJCx2gCN+6gXZX2N+BIJvmy8XmAO5sT2GYimiV7HlJH1AA6JhaEQ07QFxc3VjYW4vZGxnQDEuMC4wLXJjLjGpY2F1ZHg4ZGlkOmtleTp6Nk1rZ3VwY2hoNUh3dUhhaFM3WXN5RThiTHVhMU1yOHAyaUtOUmh5dlN2UkFzOW5jY21kaC9mb28vYmFyY2V4cBpnROP/Y2lzc3g4ZGlkOmtleTp6Nk1rdkpQbUVaWlliZ2l3MW91VDFvb3VUc1RGQkhKU3RzOW9waFZzTmdjUm1ZeFVjbmJmGmdE1itjcG9sg4NiPT1nLnN0YXR1c2VkcmFmdINjYWxsaS5yZXZpZXdlcoNkbGlrZWYuZW1haWxtKkBleGFtcGxlLmNvbYNjYW55ZS50YWdzgmJvcoKDYj09YS5kbmV3c4NiPT1hLmVwcmVzc2NzdWJ4OGRpZDprZXk6ejZNa3V1a2syc2tEWExRbjdOSzNFaDlqTW5kWWZ2REJ4eGt0Z3BpZEpBcWI3TTNwZG1ldGGiY2Jhehh7Y2Zvb2NiYXJlbm9uY2VMv+Diy6GExIuM1eX4 // Converted to DAG-JSON out: // [ // { // "/": { // "bytes": "5rvl8uKmDVGvAVSt4m/0MGiXl9dZwljJJ9m2qHCoIB617l26UvMxyH5uvN9hM7ozfVATiq4mLhoGgm9IGnEEAg" // } // }, // { // "h": { // "/": { // "bytes": "NO0BcQ" // } // }, // "ucan/dlg@1.0.0-rc.1": { // "aud": "did:key:z6Mkq5YmbJcTrPExNDi26imrTCpKhepjBFBSHqrBDN2ArPkv", // "cmd": "/foo/bar", // "exp": 1728933098, // "iss": "did:key:z6MkhVFznPeR572rTK51UjoTNpnF8cxuWfPm9oBMPr7y8ABe", // "meta": { // "baz": 123, // "foo": "bar" // }, // "nbf": 1728929558, // "nonce": { // "/": { // "bytes": "u0HMgJ5Y+M84I/66" // } // }, // "pol": [ // [ // "==", // ".status", // "draft" // ], // [ // "all", // ".reviewer", // [ // "like", // ".email", // "*@example.com" // ] // ], // [ // "any", // ".tags", // [ // "or", // [ // [ // "==", // ".", // "news" // ], // [ // "==", // ".", // "press" // ] // ] // ] // ] // ], // "sub": "did:key:z6MktA1uBdCpq4uJBqE9jjMiLyxZBg9a6xgPPKJjMqss6Zc2" // } // } // ]
Output:
func Powerline ¶
func Powerline(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, opts ...Option) (*Token, error)
Powerline creates a validated UCAN delegation Token from the provided parameters and options.
Powerline is a pattern for automatically delegating all future delegations to another agent regardless of Subject. This is a very powerful pattern, use it only if you understand it. Powerline delegations MUST NOT be used as the root delegation to a resource
A very common use case for Powerline is providing a stable DID across multiple agents (e.g. representing a user with multiple devices). This enables the automatic sharing of authority across their devices without needing to share keys or set up a threshold scheme. It is also flexible, since a Powerline delegation MAY be revoked.
You can read it as "(issuer) allows (audience) to perform (cmd+pol) on anything".
func Root ¶
func Root(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, opts ...Option) (*Token, error)
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.
You can read it as "(issuer) allows (audience) to perform (cmd+pol) on itself".
Example ¶
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).
// The command defines the shape of the arguments that will be evaluated against the policy cmd := command.MustParse("/foo/bar") // The policy defines what is allowed to do. pol := policy.MustConstruct( policy.Equal(".status", literal.String("draft")), policy.All(".reviewer", policy.Like(".email", "*@example.com"), ), policy.Any(".tags", policy.Or( policy.Equal(".", literal.String("news")), policy.Equal(".", literal.String("press")), )), ) tkn, err := delegation.Root(didtest.PersonaAlice.DID(), didtest.PersonaBob.DID(), cmd, pol, delegation.WithExpirationIn(time.Hour), delegation.WithNotBeforeIn(time.Minute), delegation.WithMeta("foo", "bar"), delegation.WithMeta("baz", 123), ) printThenPanicOnErr(err) // "Seal", meaning encode and wrap into a signed envelope. data, id, err := tkn.ToSealed(didtest.PersonaAlice.PrivKey()) printThenPanicOnErr(err) printCIDAndSealed(id, data) // Example output: // // issDid: did:key:z6MknWJqz17Y4AfsXSJUFKomuBR4GTkViM7kJYutzTMkCyFF // // CID (base58BTC): zdpuAkwYz8nY7uU8j3F6wVTfFY1VEoExwvUAYBEwRWfTozddE // // DAG-CBOR (base64) out: glhAVpW67FJ+myNi+azvnw2jivuiqXTuMrDZI2Qdaa8jE1Oi3mkjnm7DyqSQGADcomcuDslMWKmJ+OIyvbPG5PtSA6JhaEQ07QFxc3VjYW4vZGxnQDEuMC4wLXJjLjGpY2F1ZHg4ZGlkOmtleTp6Nk1rdkpQbUVaWlliZ2l3MW91VDFvb3VUc1RGQkhKU3RzOW9waFZzTmdjUm1ZeFVjY21kaC9mb28vYmFyY2V4cBpnROVoY2lzc3g4ZGlkOmtleTp6Nk1rdXVrazJza0RYTFFuN05LM0VoOWpNbmRZZnZEQnh4a3RncGlkSkFxYjdNM3BjbmJmGmdE15RjcG9sg4NiPT1nLnN0YXR1c2VkcmFmdINjYWxsaS5yZXZpZXdlcoNkbGlrZWYuZW1haWxtKkBleGFtcGxlLmNvbYNjYW55ZS50YWdzgmJvcoKDYj09YS5kbmV3c4NiPT1hLmVwcmVzc2NzdWJ4OGRpZDprZXk6ejZNa3V1a2syc2tEWExRbjdOSzNFaDlqTW5kWWZ2REJ4eGt0Z3BpZEpBcWI3TTNwZG1ldGGiY2Jhehh7Y2Zvb2NiYXJlbm9uY2VMwzDc03WBciJIGPWG // // Converted to DAG-JSON out: // [ // { // "/": { // "bytes": "VpW67FJ+myNi+azvnw2jivuiqXTuMrDZI2Qdaa8jE1Oi3mkjnm7DyqSQGADcomcuDslMWKmJ+OIyvbPG5PtSAw" // } // }, // { // "h": { // "/": { // "bytes": "NO0BcQ" // } // }, // "ucan/dlg@1.0.0-rc.1": { // "aud": "did:key:z6MkvJPmEZZYbgiw1ouT1oouTsTFBHJSts9ophVsNgcRmYxU", // "cmd": "/foo/bar", // "exp": 1732568424, // "iss": "did:key:z6Mkuukk2skDXLQn7NK3Eh9jMndYfvDBxxktgpidJAqb7M3p", // "meta": { // "baz": 123, // "foo": "bar" // }, // "nbf": 1732564884, // "nonce": { // "/": { // "bytes": "wzDc03WBciJIGPWG" // } // }, // "pol": [ // [ // "==", // ".status", // "draft" // ], // [ // "all", // ".reviewer", // [ // "like", // ".email", // "*@example.com" // ] // ], // [ // "any", // ".tags", // [ // "or", // [ // [ // "==", // ".", // "news" // ], // [ // "==", // ".", // "press" // ] // ] // ] // ] // ], // "sub": "did:key:z6Mkuukk2skDXLQn7NK3Eh9jMndYfvDBxxktgpidJAqb7M3p" // } // } // ]
Output:
func (*Token) Encode ¶
Encode marshals a Token to the format specified by the provided codec.Encoder.
func (*Token) EncodeWriter ¶
EncodeWriter is the same as Encode, but accepts an io.Writer.
func (*Token) Expiration ¶
Expiration returns the time at which the Token expires.
func (*Token) IsValidAt ¶
IsValidNow verifies that the token can be used at the given time, based on expiration or "not before" fields. This does NOT do any other kind of verifications.
func (*Token) IsValidNow ¶
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 (*Token) Subject ¶
Subject returns the did.DID representing the Token's subject.
This field may be did.Undef for delegations that are [Powerlined] but must be equal to the value returned by the Issuer method for root tokens.
func (*Token) ToDagCborWriter ¶
ToDagCborWriter is the same as ToDagCbor, but it accepts an io.Writer.
func (*Token) ToDagJsonWriter ¶
ToDagJsonWriter is the same as ToDagJson, but it accepts an io.Writer.
Directories ¶
Path | Synopsis |
---|---|
Package delegationtest provides a set of pre-built delegation tokens for a variety of test cases.
|
Package delegationtest provides a set of pre-built delegation tokens for a variety of test cases. |