From fff054ea17a37a62475d950363fb52bd358a8ece Mon Sep 17 00:00:00 2001 From: b5 Date: Fri, 4 Dec 2020 10:49:03 -0500 Subject: [PATCH 1/2] refactor: rename UCAN -> Token When using this package, `ucan.Token` reads better than `ucan.UCAN` to me. Encourages the reader to think in terms of "tokens", from the "ucan" package. Performed this refactoring with a few commands (and a few comment edits): $ gofmt -r 'UCAN -> Token' -w . $ gofmt -r 'NewAttenuatedUCAN -> NewAttenuatedToken' -w . $ gofmt -r 'NewOriginUCAN -> NewOriginToken' -w . $ gofmt -r 'UCANParser -> TokenParser' -w . $ gofmt -r 'NewUCANParser -> NewTokenParser' -w . $ gofmt -r 'UCANCtxKey -> TokenCtxKey' -w . Changed example test "ExampleWalkthrough" to "Example" to make go vet happy BREAKING CHANGE: UCAN symbol is now "Token" --- context.go | 20 ++++++++++---------- example_test.go | 12 ++++++------ token.go | 39 ++++++++++++++++++++------------------- token_test.go | 8 ++++---- 4 files changed, 40 insertions(+), 39 deletions(-) diff --git a/context.go b/context.go index cd18521..e6093fe 100644 --- a/context.go +++ b/context.go @@ -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 diff --git a/example_test.go b/example_test.go index 69e4bdd..50c5441 100644 --- a/example_test.go +++ b/example_test.go @@ -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)) } diff --git a/token.go b/token.go index ec5bdb4..49997d3 100644 --- a/token.go +++ b/token.go @@ -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 { @@ -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, @@ -277,14 +278,14 @@ func (StringDIDPubKeyResolver) ResolveDIDKey(ctx context.Context, didStr string) return crypto.UnmarshalRsaPublicKey(data) } -type UCANParser struct { +type TokenParser struct { ap AttenuationConstructor cidr CIDBytesResolver didr DIDPubKeyResolver } -func NewUCANParser(ap AttenuationConstructor, didr DIDPubKeyResolver, cidr CIDBytesResolver) *UCANParser { - return &UCANParser{ +func NewTokenParser(ap AttenuationConstructor, didr DIDPubKeyResolver, cidr CIDBytesResolver) *TokenParser { + return &TokenParser{ ap: ap, cidr: cidr, didr: didr, @@ -292,11 +293,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 +338,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 { diff --git a/token_test.go b/token_test.go index fe27024..f099881 100644 --- a/token_test.go +++ b/token_test.go @@ -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 { From 1b20573d3e2cb6e4ed4ebd517b673ece7cdd459f Mon Sep 17 00:00:00 2001 From: b5 Date: Fri, 4 Dec 2020 11:17:57 -0500 Subject: [PATCH 2/2] docs: ensure all exported symbols are documented makes golint happy. --- attenuation.go | 4 ++-- token.go | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/attenuation.go b/attenuation.go index 545ab81..43a8d0a 100644 --- a/attenuation.go +++ b/attenuation.go @@ -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 { diff --git a/token.go b/token.go index 49997d3..e639bb5 100644 --- a/token.go +++ b/token.go @@ -128,7 +128,7 @@ type pkSource struct { verifyKey *rsa.PublicKey signKey *rsa.PrivateKey - ap AttenuationConstructor + ap AttenuationConstructorFunc resolver CIDBytesResolver store TokenStore } @@ -250,10 +250,13 @@ func (a *pkSource) newToken(subjectDID string, prf []Proof, att Attenuations, fc }, 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 { @@ -262,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 { @@ -278,13 +285,15 @@ func (StringDIDPubKeyResolver) ResolveDIDKey(ctx context.Context, didStr string) return crypto.UnmarshalRsaPublicKey(data) } +// TokenParser parses a raw string into a Token type TokenParser struct { - ap AttenuationConstructor + ap AttenuationConstructorFunc cidr CIDBytesResolver didr DIDPubKeyResolver } -func NewTokenParser(ap AttenuationConstructor, didr DIDPubKeyResolver, cidr CIDBytesResolver) *TokenParser { +// NewTokenParser constructs a token parser +func NewTokenParser(ap AttenuationConstructorFunc, didr DIDPubKeyResolver, cidr CIDBytesResolver) *TokenParser { return &TokenParser{ ap: ap, cidr: cidr,