Merge pull request #8 from dholms/audience
Change "subject" to "audience"
This commit is contained in:
@@ -12,7 +12,7 @@ func Example() {
|
||||
source, err := ucan.NewPrivKeySource(keyOne)
|
||||
panicIfError(err)
|
||||
|
||||
subjectDID, err := ucan.DIDStringFromPublicKey(keyOne.GetPublic())
|
||||
audienceDID, err := ucan.DIDStringFromPublicKey(keyOne.GetPublic())
|
||||
panicIfError(err)
|
||||
|
||||
caps := ucan.NewNestedCapabilities("SUPER_USER", "OVERWRITE", "SOFT_DELETE", "REVISE", "CREATE")
|
||||
@@ -23,7 +23,7 @@ func Example() {
|
||||
zero := time.Time{}
|
||||
|
||||
// create a root UCAN
|
||||
origin, err := source.NewOriginToken(subjectDID, att, nil, zero, zero)
|
||||
origin, err := source.NewOriginToken(audienceDID, att, nil, zero, zero)
|
||||
panicIfError(err)
|
||||
|
||||
id, err := origin.CID()
|
||||
@@ -35,7 +35,7 @@ func Example() {
|
||||
{caps.Cap("SUPER_USER"), ucan.NewStringLengthResource("dataset", "third:resource")},
|
||||
}
|
||||
|
||||
if _, err = source.NewAttenuatedToken(origin, subjectDID, att, nil, zero, zero); err != nil {
|
||||
if _, err = source.NewAttenuatedToken(origin, audienceDID, att, nil, zero, zero); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func Example() {
|
||||
{caps.Cap("OVERWRITE"), ucan.NewStringLengthResource("dataset", "b5:world_bank_population:*")},
|
||||
}
|
||||
|
||||
derivedToken, err := source.NewAttenuatedToken(origin, subjectDID, att, nil, zero, zero)
|
||||
derivedToken, err := source.NewAttenuatedToken(origin, audienceDID, att, nil, zero, zero)
|
||||
panicIfError(err)
|
||||
|
||||
id, err = derivedToken.CID()
|
||||
@@ -58,9 +58,9 @@ func Example() {
|
||||
fmt.Printf("issuer DID key type: %s\n", tok.Issuer.Type().String())
|
||||
|
||||
// Output:
|
||||
// cid of root UCAN: bafkreid6l4npxfwei2ccpelqkhirthcaa2lpmg3xa4rz4lrsqz2rgujp5m
|
||||
// cid of root UCAN: bafkreihl4b2ncrijeutlkppykgspz6wm3q2o4wiej6njl6tj7k2xa3zcue
|
||||
// scope of ucan attenuations must be less than it's parent
|
||||
// cid of derived UCAN: bafkreibeirwwbnz2cmboq5t47d3rsjxrd4rcnreptuozwcc2lr3pbnzuki
|
||||
// cid of derived UCAN: bafkreifhpoxctmbmvocdevfbmio6cpzltwauesyyjycipnylocoykwghzu
|
||||
// issuer DID key type: RSA
|
||||
}
|
||||
|
||||
|
||||
40
token.go
40
token.go
@@ -46,9 +46,9 @@ const (
|
||||
// token a UCAN
|
||||
type Token struct {
|
||||
// Entire UCAN as a signed JWT string
|
||||
Raw string
|
||||
Issuer didkey.ID
|
||||
Subject didkey.ID
|
||||
Raw string
|
||||
Issuer didkey.ID
|
||||
Audience didkey.ID
|
||||
// the "inputs" to this token, a chain UCAN tokens with broader scopes &
|
||||
// deadlines than this token
|
||||
Proofs []Proof `json:"prf,omitempty"`
|
||||
@@ -118,8 +118,8 @@ type CIDBytesResolver interface {
|
||||
// implementations of Source must conform to the assertion test defined in the
|
||||
// spec subpackage
|
||||
type Source interface {
|
||||
NewOriginToken(subjectDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*Token, error)
|
||||
NewAttenuatedToken(parent *Token, subjectDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*Token, error)
|
||||
NewOriginToken(audienceDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*Token, error)
|
||||
NewAttenuatedToken(parent *Token, audienceDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*Token, error)
|
||||
}
|
||||
|
||||
type pkSource struct {
|
||||
@@ -196,24 +196,24 @@ func NewPrivKeySource(privKey crypto.PrivKey) (Source, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *pkSource) NewOriginToken(subjectDID string, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) {
|
||||
return a.newToken(subjectDID, nil, att, fct, nbf, exp)
|
||||
func (a *pkSource) NewOriginToken(audienceDID string, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) {
|
||||
return a.newToken(audienceDID, nil, att, fct, nbf, exp)
|
||||
}
|
||||
|
||||
func (a *pkSource) NewAttenuatedToken(parent *Token, subjectDID string, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) {
|
||||
func (a *pkSource) NewAttenuatedToken(parent *Token, audienceDID string, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) {
|
||||
if !parent.Attenuations.Contains(att) {
|
||||
return nil, fmt.Errorf("scope of ucan attenuations must be less than it's parent")
|
||||
}
|
||||
return a.newToken(subjectDID, append(parent.Proofs, Proof(parent.Raw)), att, fct, nbf, exp)
|
||||
return a.newToken(audienceDID, append(parent.Proofs, Proof(parent.Raw)), att, fct, nbf, exp)
|
||||
}
|
||||
|
||||
// CreateToken returns a new JWT token
|
||||
func (a *pkSource) newToken(subjectDID string, prf []Proof, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) {
|
||||
func (a *pkSource) newToken(audienceDID string, prf []Proof, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) {
|
||||
// create a signer for rsa 256
|
||||
t := jwt.New(a.signingMethod)
|
||||
|
||||
// if _, err := did.Parse(subjectDID); err != nil {
|
||||
// return nil, fmt.Errorf("invalid subject DID: %w", err)
|
||||
// if _, err := did.Parse(audienceDID); err != nil {
|
||||
// return nil, fmt.Errorf("invalid audience DID: %w", err)
|
||||
// }
|
||||
|
||||
t.Header[UCANVersionKey] = UCANVersion
|
||||
@@ -234,7 +234,7 @@ func (a *pkSource) newToken(subjectDID string, prf []Proof, att Attenuations, fc
|
||||
t.Claims = &Claims{
|
||||
StandardClaims: &jwt.StandardClaims{
|
||||
Issuer: a.issuerDID,
|
||||
Subject: subjectDID,
|
||||
Audience: audienceDID,
|
||||
NotBefore: nbfUnix,
|
||||
// set the expire time
|
||||
// see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20#section-4.1.4
|
||||
@@ -317,7 +317,7 @@ func (p *TokenParser) parseAndVerify(ctx context.Context, raw string, child *Tok
|
||||
|
||||
var iss didkey.ID
|
||||
// TODO(b5): we're double parsing here b/c the jwt lib we're using doesn't expose
|
||||
// an API (that I know of) for storing parsed issuer / subjects
|
||||
// an API (that I know of) for storing parsed issuer / audience
|
||||
if issStr, ok := mc["iss"].(string); ok {
|
||||
iss, err = didkey.Parse(issStr)
|
||||
if err != nil {
|
||||
@@ -327,16 +327,16 @@ func (p *TokenParser) parseAndVerify(ctx context.Context, raw string, child *Tok
|
||||
return nil, fmt.Errorf(`"iss" key is not in claims`)
|
||||
}
|
||||
|
||||
var sub didkey.ID
|
||||
var aud didkey.ID
|
||||
// TODO(b5): we're double parsing here b/c the jwt lib we're using doesn't expose
|
||||
// an API (that I know of) for storing parsed issuer / subjects
|
||||
if subStr, ok := mc["sub"].(string); ok {
|
||||
sub, err = didkey.Parse(subStr)
|
||||
// an API (that I know of) for storing parsed issuer / audience
|
||||
if audStr, ok := mc["aud"].(string); ok {
|
||||
aud, err = didkey.Parse(audStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf(`"sub" key is not in claims`)
|
||||
return nil, fmt.Errorf(`"aud" key is not in claims`)
|
||||
}
|
||||
|
||||
var att Attenuations
|
||||
@@ -372,7 +372,7 @@ func (p *TokenParser) parseAndVerify(ctx context.Context, raw string, child *Tok
|
||||
return &Token{
|
||||
Raw: raw,
|
||||
Issuer: iss,
|
||||
Subject: sub,
|
||||
Audience: aud,
|
||||
Attenuations: att,
|
||||
Proofs: prf,
|
||||
}, nil
|
||||
|
||||
@@ -62,7 +62,7 @@ func TestPrivKeySource(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expect := `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInVjdiI6IjAuNy4wIn0.eyJpc3MiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJzdWIiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJhdHQiOlt7ImFwaSI6IioiLCJjYXAiOiJTVVBFUl9VU0VSIn0seyJjYXAiOiJTVVBFUl9VU0VSIiwiZGF0YXNldCI6ImI1OndvcmxkX2JhbmtfcG9wdWxhdGlvbjoqIn1dfQ.ndbCaw73SX-cmGz0tQq16nsQsp3Thw1lyza_W8juvoemGo5aiT-ayOSvgl4oeShoBfBiz7NQ7T6FUDfpiUF8cwfP2WLbW-TXDan9arTKw_KLZ3j-re5ACFRVKDWy6sSfJ1BncX9ADt2nmistxYc5uE4wO0RPl9ulSjWsL4mVq6pf77ajPehUYvDgSerGzcvNOmxibDC760gb-F_2jijnA-TEwYvitFaZ_3MmmKhUiMuPP_XqYVWnmuNhje-N1yQg_tEJCsuj25zqFefW9jLPnvkywgyrPyMcrXj1ZQMCX9n37TQbC2WUZE7KvuBkuK11dAkrtXkBH-Gr9QiDWLsdPw`
|
||||
expect := `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInVjdiI6IjAuNy4wIn0.eyJhdWQiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJpc3MiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJhdHQiOlt7ImFwaSI6IioiLCJjYXAiOiJTVVBFUl9VU0VSIn0seyJjYXAiOiJTVVBFUl9VU0VSIiwiZGF0YXNldCI6ImI1OndvcmxkX2JhbmtfcG9wdWxhdGlvbjoqIn1dfQ.ggJJ8fovwKVbq_hLb0sVKlvkFRcKJWb-55RgIagjzO9D9I0pZ5g3elkOCkf1XA60_32fE-K_Dj97np6-BQx_F5u_PofYi6C0BYfR4YATA5jzymT7nBLrdOzhr0Vh2FChYoyM82CT4tkOGSlnvaoCgB4OLMOzlvpWmbfRi5GB3d6yAfdhBGsDuAJ9L7V_N5WBFpjarSu2xAYhVUhFM8IbILHMipXWRd2sP-_DzxmsneS7qu9fxAk35DDC_8cONPp1ZrFUw-VhGts0jYOVuExl_ZWqE3y2XJLtiperxFWO45q59WdULrn15ciQjRhn2O-QmXHmOxLNZMCI6lbFFiCHWg`
|
||||
if expect != root.Raw {
|
||||
t.Errorf("token mismatch. expected: %q.\ngot: %q", expect, root.Raw)
|
||||
}
|
||||
@@ -77,7 +77,7 @@ func TestPrivKeySource(t *testing.T) {
|
||||
}
|
||||
|
||||
cidStr := mustCidString(t, derivedToken)
|
||||
expectCID := "bafkreibeirwwbnz2cmboq5t47d3rsjxrd4rcnreptuozwcc2lr3pbnzuki"
|
||||
expectCID := "bafkreifhpoxctmbmvocdevfbmio6cpzltwauesyyjycipnylocoykwghzu"
|
||||
|
||||
if expectCID != cidStr {
|
||||
t.Errorf("derived token CID mismatch. expected: %q.\ngot: %q", expectCID, cidStr)
|
||||
@@ -101,7 +101,7 @@ func TestED25519PrivKeySource(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
subjectDID, err := ucan.DIDStringFromPublicKey(keyOne.GetPublic())
|
||||
audienceDID, err := ucan.DIDStringFromPublicKey(keyOne.GetPublic())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func TestED25519PrivKeySource(t *testing.T) {
|
||||
zero := time.Time{}
|
||||
|
||||
// create a root UCAN
|
||||
origin, err := source.NewOriginToken(subjectDID, nil, nil, zero, zero)
|
||||
origin, err := source.NewOriginToken(audienceDID, nil, nil, zero, zero)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -130,7 +130,7 @@ func TestTokenSource(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTokenParse(t *testing.T) {
|
||||
raw := `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInVjdiI6IjAuNy4wIn0.eyJpc3MiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJzdWIiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJhdHQiOlt7ImFwaSI6IioiLCJjYXAiOiJTVVBFUl9VU0VSIn0seyJjYXAiOiJTVVBFUl9VU0VSIiwiZGF0YXNldCI6ImI1OndvcmxkX2JhbmtfcG9wdWxhdGlvbjoqIn1dfQ.ndbCaw73SX-cmGz0tQq16nsQsp3Thw1lyza_W8juvoemGo5aiT-ayOSvgl4oeShoBfBiz7NQ7T6FUDfpiUF8cwfP2WLbW-TXDan9arTKw_KLZ3j-re5ACFRVKDWy6sSfJ1BncX9ADt2nmistxYc5uE4wO0RPl9ulSjWsL4mVq6pf77ajPehUYvDgSerGzcvNOmxibDC760gb-F_2jijnA-TEwYvitFaZ_3MmmKhUiMuPP_XqYVWnmuNhje-N1yQg_tEJCsuj25zqFefW9jLPnvkywgyrPyMcrXj1ZQMCX9n37TQbC2WUZE7KvuBkuK11dAkrtXkBH-Gr9QiDWLsdPw`
|
||||
raw := `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInVjdiI6IjAuNy4wIn0.eyJhdWQiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJpc3MiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJhdHQiOlt7ImFwaSI6IioiLCJjYXAiOiJTVVBFUl9VU0VSIn0seyJjYXAiOiJTVVBFUl9VU0VSIiwiZGF0YXNldCI6ImI1OndvcmxkX2JhbmtfcG9wdWxhdGlvbjoqIn1dfQ.ggJJ8fovwKVbq_hLb0sVKlvkFRcKJWb-55RgIagjzO9D9I0pZ5g3elkOCkf1XA60_32fE-K_Dj97np6-BQx_F5u_PofYi6C0BYfR4YATA5jzymT7nBLrdOzhr0Vh2FChYoyM82CT4tkOGSlnvaoCgB4OLMOzlvpWmbfRi5GB3d6yAfdhBGsDuAJ9L7V_N5WBFpjarSu2xAYhVUhFM8IbILHMipXWRd2sP-_DzxmsneS7qu9fxAk35DDC_8cONPp1ZrFUw-VhGts0jYOVuExl_ZWqE3y2XJLtiperxFWO45q59WdULrn15ciQjRhn2O-QmXHmOxLNZMCI6lbFFiCHWg`
|
||||
|
||||
caps := ucan.NewNestedCapabilities("SUPER_USER", "OVERWRITE", "SOFT_DELETE", "REVISE", "CREATE")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user