refactor: rename UCAN -> Token

Merge pull request #3 from qri-io/refactor_token
This commit is contained in:
Brendan O'Brien
2020-12-04 14:49:21 -05:00
committed by GitHub
5 changed files with 53 additions and 43 deletions

View File

@@ -36,10 +36,10 @@ LOOP:
return true
}
// AttenuationConstructor is a function that creates an attenuation from a map
// AttenuationConstructorFunc is a function that creates an attenuation from a map
// Users of this package provide an Attenuation Constructor to the parser to
// bind attenuation logic to a UCAN
type AttenuationConstructor func(v map[string]interface{}) (Attenuation, error)
type AttenuationConstructorFunc func(v map[string]interface{}) (Attenuation, error)
// Attenuation is a capability on a resource
type Attenuation struct {

View File

@@ -8,19 +8,19 @@ import (
// package
type CtxKey string
// UCANCtxKey is the key for adding an access UCAN to a context.Context
const UCANCtxKey CtxKey = "UCAN"
// TokenCtxKey is the key for adding an access UCAN to a context.Context
const TokenCtxKey CtxKey = "UCAN"
// CtxWithUCAN adds a UCAN value to a context
func CtxWithUCAN(ctx context.Context, t UCAN) context.Context {
return context.WithValue(ctx, UCANCtxKey, t)
// CtxWithToken adds a UCAN value to a context
func CtxWithToken(ctx context.Context, t Token) context.Context {
return context.WithValue(ctx, TokenCtxKey, t)
}
// FromCtx extracts a Dataset reference from a given
// context if one is set, returning nil otherwise
func FromCtx(ctx context.Context) *UCAN {
iface := ctx.Value(UCANCtxKey)
if ref, ok := iface.(*UCAN); ok {
// FromCtx extracts a token from a given context if one is set, returning nil
// otherwise
func FromCtx(ctx context.Context) *Token {
iface := ctx.Value(TokenCtxKey)
if ref, ok := iface.(*Token); ok {
return ref
}
return nil

View File

@@ -8,7 +8,7 @@ import (
"github.com/qri-io/ucan"
)
func ExampleWalkthrough() {
func Example() {
source, err := ucan.NewPrivKeySource(keyOne)
panicIfError(err)
@@ -23,7 +23,7 @@ func ExampleWalkthrough() {
zero := time.Time{}
// create a root UCAN
origin, err := source.NewOriginUCAN(subjectDID, att, nil, zero, zero)
origin, err := source.NewOriginToken(subjectDID, att, nil, zero, zero)
panicIfError(err)
id, err := origin.CID()
@@ -35,7 +35,7 @@ func ExampleWalkthrough() {
{caps.Cap("SUPER_USER"), ucan.NewStringLengthResource("dataset", "third:resource")},
}
if _, err = source.NewAttenuatedUCAN(origin, subjectDID, att, nil, zero, zero); err != nil {
if _, err = source.NewAttenuatedToken(origin, subjectDID, att, nil, zero, zero); err != nil {
fmt.Println(err)
}
@@ -43,7 +43,7 @@ func ExampleWalkthrough() {
{caps.Cap("OVERWRITE"), ucan.NewStringLengthResource("dataset", "b5:world_bank_population:*")},
}
derivedToken, err := source.NewAttenuatedUCAN(origin, subjectDID, att, nil, zero, zero)
derivedToken, err := source.NewAttenuatedToken(origin, subjectDID, att, nil, zero, zero)
panicIfError(err)
id, err = derivedToken.CID()
@@ -67,7 +67,7 @@ func panicIfError(err error) {
}
}
func exampleParser() *ucan.UCANParser {
func exampleParser() *ucan.TokenParser {
caps := ucan.NewNestedCapabilities("SUPER_USER", "OVERWRITE", "SOFT_DELETE", "REVISE", "CREATE")
ac := func(m map[string]interface{}) (ucan.Attenuation, error) {
@@ -95,5 +95,5 @@ func exampleParser() *ucan.UCANParser {
}
store := ucan.NewMemTokenStore()
return ucan.NewUCANParser(ac, ucan.StringDIDPubKeyResolver{}, store.(ucan.CIDBytesResolver))
return ucan.NewTokenParser(ac, ucan.StringDIDPubKeyResolver{}, store.(ucan.CIDBytesResolver))
}

View File

@@ -42,8 +42,9 @@ const (
CapKey = "cap"
)
// UCAN is a JSON Web Token (JWT) that contains special keys
type UCAN struct {
// Token is a JSON Web Token (JWT) that contains special keys that make the
// token a UCAN
type Token struct {
// Entire UCAN as a signed JWT string
Raw string
// the "inputs" to this token, a chain UCAN tokens with broader scopes &
@@ -57,7 +58,7 @@ type UCAN struct {
}
// CID calculates the cid of a UCAN using the default prefix
func (t *UCAN) CID() (cid.Cid, error) {
func (t *Token) CID() (cid.Cid, error) {
pref := cid.Prefix{
Version: 1,
Codec: cid.Raw,
@@ -69,7 +70,7 @@ func (t *UCAN) CID() (cid.Cid, error) {
}
// PrefixCID calculates the CID of a token with a supplied prefix
func (t *UCAN) PrefixCID(pref cid.Prefix) (cid.Cid, error) {
func (t *Token) PrefixCID(pref cid.Prefix) (cid.Cid, error) {
return pref.Sum([]byte(t.Raw))
}
@@ -115,8 +116,8 @@ type CIDBytesResolver interface {
// implementations of Source must conform to the assertion test defined in the
// spec subpackage
type Source interface {
NewOriginUCAN(subjectDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*UCAN, error)
NewAttenuatedUCAN(parent *UCAN, subjectDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*UCAN, error)
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)
}
type pkSource struct {
@@ -127,7 +128,7 @@ type pkSource struct {
verifyKey *rsa.PublicKey
signKey *rsa.PrivateKey
ap AttenuationConstructor
ap AttenuationConstructorFunc
resolver CIDBytesResolver
store TokenStore
}
@@ -187,19 +188,19 @@ func NewPrivKeySource(privKey crypto.PrivKey) (Source, error) {
}, nil
}
func (a *pkSource) NewOriginUCAN(subjectDID string, att Attenuations, fct []Fact, nbf, exp time.Time) (*UCAN, error) {
return a.newUCAN(subjectDID, nil, att, fct, nbf, exp)
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) NewAttenuatedUCAN(parent *UCAN, subjectDID string, att Attenuations, fct []Fact, nbf, exp time.Time) (*UCAN, error) {
func (a *pkSource) NewAttenuatedToken(parent *Token, subjectDID 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.newUCAN(subjectDID, append(parent.Proofs, Proof(parent.Raw)), att, fct, nbf, exp)
return a.newToken(subjectDID, append(parent.Proofs, Proof(parent.Raw)), att, fct, nbf, exp)
}
// CreateToken returns a new JWT token
func (a *pkSource) newUCAN(subjectDID string, prf []Proof, att Attenuations, fct []Fact, nbf, exp time.Time) (*UCAN, error) {
func (a *pkSource) newToken(subjectDID string, prf []Proof, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) {
// create a signer for rsa 256
t := jwt.New(a.signingMethod)
@@ -241,7 +242,7 @@ func (a *pkSource) newUCAN(subjectDID string, prf []Proof, att Attenuations, fct
return nil, err
}
return &UCAN{
return &Token{
Raw: raw,
Attenuations: att,
Facts: fct,
@@ -249,10 +250,13 @@ func (a *pkSource) newUCAN(subjectDID string, prf []Proof, att Attenuations, fct
}, nil
}
// DIDPubKeyResolver turns did:key Decentralized IDentifiers into a public key,
// possibly using a network request
type DIDPubKeyResolver interface {
ResolveDIDKey(ctx context.Context, did string) (crypto.PubKey, error)
}
// DIDStringFromPublicKey creates a did:key identifier string from a public key
func DIDStringFromPublicKey(pub crypto.PubKey) (string, error) {
rawPubBytes, err := pub.Raw()
if err != nil {
@@ -261,8 +265,12 @@ func DIDStringFromPublicKey(pub crypto.PubKey) (string, error) {
return fmt.Sprintf("did:key:%s", base64.URLEncoding.EncodeToString(rawPubBytes)), nil
}
// StringDIDPubKeyResolver implements the DIDPubKeyResolver interface without
// any network backing. Works if the key string given contains the public key
// itself
type StringDIDPubKeyResolver struct{}
// ResolveDIDKey extracts a public key from a did:key string
func (StringDIDPubKeyResolver) ResolveDIDKey(ctx context.Context, didStr string) (crypto.PubKey, error) {
// id, err := did.Parse(didStr)
// if err != nil {
@@ -277,14 +285,16 @@ func (StringDIDPubKeyResolver) ResolveDIDKey(ctx context.Context, didStr string)
return crypto.UnmarshalRsaPublicKey(data)
}
type UCANParser struct {
ap AttenuationConstructor
// TokenParser parses a raw string into a Token
type TokenParser struct {
ap AttenuationConstructorFunc
cidr CIDBytesResolver
didr DIDPubKeyResolver
}
func NewUCANParser(ap AttenuationConstructor, didr DIDPubKeyResolver, cidr CIDBytesResolver) *UCANParser {
return &UCANParser{
// NewTokenParser constructs a token parser
func NewTokenParser(ap AttenuationConstructorFunc, didr DIDPubKeyResolver, cidr CIDBytesResolver) *TokenParser {
return &TokenParser{
ap: ap,
cidr: cidr,
didr: didr,
@@ -292,11 +302,11 @@ func NewUCANParser(ap AttenuationConstructor, didr DIDPubKeyResolver, cidr CIDBy
}
// ParseAndVerify will parse, validate and return a token
func (p *UCANParser) ParseAndVerify(ctx context.Context, raw string) (*UCAN, error) {
func (p *TokenParser) ParseAndVerify(ctx context.Context, raw string) (*Token, error) {
return p.parseAndVerify(ctx, raw, nil)
}
func (p *UCANParser) parseAndVerify(ctx context.Context, raw string, child *UCAN) (*UCAN, error) {
func (p *TokenParser) parseAndVerify(ctx context.Context, raw string, child *Token) (*Token, error) {
tok, err := jwt.Parse(raw, p.matchVerifyKeyFunc(ctx))
if err != nil {
return nil, err
@@ -337,14 +347,14 @@ func (p *UCANParser) parseAndVerify(ctx context.Context, raw string, child *UCAN
return nil, fmt.Errorf(`"prf" key is not an array`)
}
return &UCAN{
return &Token{
Raw: raw,
Attenuations: att,
Proofs: prf,
}, nil
}
func (p *UCANParser) matchVerifyKeyFunc(ctx context.Context) func(tok *jwt.Token) (interface{}, error) {
func (p *TokenParser) matchVerifyKeyFunc(ctx context.Context) func(tok *jwt.Token) (interface{}, error) {
return func(tok *jwt.Token) (interface{}, error) {
mc, ok := tok.Claims.(jwt.MapClaims)
if !ok {

View File

@@ -57,7 +57,7 @@ func TestPrivKeySource(t *testing.T) {
}
zero := time.Time{}
root, err := source.NewOriginUCAN(didStr, att, nil, zero, zero)
root, err := source.NewOriginToken(didStr, att, nil, zero, zero)
if err != nil {
t.Fatal(err)
}
@@ -71,7 +71,7 @@ func TestPrivKeySource(t *testing.T) {
{caps.Cap("OVERWRITE"), ucan.NewStringLengthResource("dataset", "b5:world_bank_population:*")},
}
derivedToken, err := source.NewAttenuatedUCAN(root, didStr, att, nil, zero, zero)
derivedToken, err := source.NewAttenuatedToken(root, didStr, att, nil, zero, zero)
if err != nil {
t.Fatal(err)
}
@@ -130,14 +130,14 @@ func TestTokenParse(t *testing.T) {
}
store := ucan.NewMemTokenStore()
p := ucan.NewUCANParser(ac, ucan.StringDIDPubKeyResolver{}, store.(ucan.CIDBytesResolver))
p := ucan.NewTokenParser(ac, ucan.StringDIDPubKeyResolver{}, store.(ucan.CIDBytesResolver))
_, err := p.ParseAndVerify(context.Background(), raw)
if err != nil {
t.Error(err)
}
}
func mustCidString(t *testing.T, tok *ucan.UCAN) string {
func mustCidString(t *testing.T, tok *ucan.Token) string {
t.Helper()
id, err := tok.CID()
if err != nil {