feat(invocation): ipld unseal to invocation

This commit is contained in:
Steve Moyer
2024-11-04 16:07:11 -05:00
parent a98653b769
commit 187e7a869c
5 changed files with 88 additions and 21 deletions

View File

@@ -23,7 +23,7 @@ import (
func ExampleNew() {
privKey, iss, sub, cmd, args, prf, meta, err := setupExampleNew()
if err != nil {
fmt.Errorf("failed to create setup: %w", err)
fmt.Println("failed to create setup:", err.Error())
return
}
@@ -39,21 +39,21 @@ func ExampleNew() {
invocation.WithExpirationIn(time.Minute),
invocation.WithoutInvokedAt())
if err != nil {
fmt.Errorf("failed to create invocation: %w", err)
fmt.Println("failed to create invocation:", err.Error())
return
}
data, cid, err := inv.ToSealed(privKey)
if err != nil {
fmt.Errorf("failed to seal invocation: %w", err)
fmt.Println("failed to seal invocation:", err.Error())
return
}
json, err := prettyDAGJSON(data)
if err != nil {
fmt.Errorf("failed to pretty DAG-JSON: %w", err)
fmt.Println("failed to pretty DAG-JSON:", err.Error())
return
}
@@ -139,6 +139,8 @@ func prettyDAGJSON(data []byte) (string, error) {
return "", err
}
fmt.Println(string(jsonData))
var out bytes.Buffer
if err := json.Indent(&out, jsonData, "", " "); err != nil {
return "", err
@@ -171,14 +173,19 @@ func setupExampleNew() (privKey crypto.PrivKey, iss, sub did.DID, cmd command.Co
if err != nil {
errs = errors.Join(errs, fmt.Errorf("failed to build headers: %w", err))
}
// ***** WARNING - do not change the order of these elements. DAG-CBOR
// will order them alphabetically and the unsealed
// result won't match if the input isn't also created in
// alphabetical order.
payload, err := qp.BuildMap(basicnode.Prototype.Any, 4, func(ma datamodel.MapAssembler) {
qp.MapEntry(ma, "title", qp.String("UCAN for Fun and Profit"))
qp.MapEntry(ma, "body", qp.String("UCAN is great"))
qp.MapEntry(ma, "draft", qp.Bool(true))
qp.MapEntry(ma, "title", qp.String("UCAN for Fun and Profit"))
qp.MapEntry(ma, "topics", qp.List(2, func(la datamodel.ListAssembler) {
qp.ListEntry(la, qp.String("authz"))
qp.ListEntry(la, qp.String("journal"))
}))
qp.MapEntry(ma, "draft", qp.Bool(true))
})
if err != nil {
errs = errors.Join(errs, fmt.Errorf("failed to build payload: %w", err))
@@ -202,6 +209,10 @@ func setupExampleNew() (privKey crypto.PrivKey, iss, sub did.DID, cmd command.Co
}
}
// ***** WARNING - do not change the order of these elements. DAG-CBOR
// will order them alphabetically and the unsealed
// result won't match if the input isn't also created in
// alphabetical order.
tags, err := qp.BuildList(basicnode.Prototype.Any, 3, func(la datamodel.ListAssembler) {
qp.ListEntry(la, qp.String("blog"))
qp.ListEntry(la, qp.String("post"))

View File

@@ -62,9 +62,8 @@ type Token struct {
// With the exception of the WithMeta option, all other will overwrite
// the previous contents of their target field.
func New(iss, sub did.DID, cmd command.Command, prf []cid.Cid, opts ...Option) (*Token, error) {
nonce := make([]byte, 12)
if _, err := rand.Read(nonce); err != nil {
nonce, err := generateNonce()
if err != nil {
return nil, err
}
@@ -141,6 +140,7 @@ func (t *Token) InvokedAt() *time.Time {
return t.invokedAt
}
// Cause returns the (optional)
func (t *Token) Cause() *cid.Cid {
return t.cause
}
@@ -170,9 +170,41 @@ func (t *Token) validate() error {
func tokenFromModel(m tokenPayloadModel) (*Token, error) {
var (
tkn Token
err error
)
// TODO
if tkn.issuer, err = did.Parse(m.Iss); err != nil {
return nil, err
}
if tkn.subject, err = did.Parse(m.Sub); err != nil {
return nil, err
}
if tkn.audience, err = parseOptionalDID(m.Aud); err != nil {
return nil, err
}
if tkn.command, err = command.Parse(m.Cmd); err != nil {
return nil, err
}
tkn.arguments = m.Args.Values
tkn.proof = m.Prf
tkn.meta = m.Meta
tkn.nonce = m.Nonce
if tkn.expiration, err = parseOptionalTimestamp(m.Exp); err != nil {
return nil, err
}
if tkn.invokedAt, err = parseOptionalTimestamp(m.Iat); err != nil {
return nil, err
}
if tkn.cause, err = parseOptionalCID(m.Cause); err != nil {
return nil, err
}
return &tkn, nil
}
@@ -187,3 +219,29 @@ func generateNonce() ([]byte, error) {
}
return res, nil
}
func parseOptionalCID(c *cid.Cid) (*cid.Cid, error) {
if c == nil {
return nil, nil
}
return c, nil
}
func parseOptionalDID(s *string) (did.DID, error) {
if s == nil {
return did.Undef, nil
}
return did.Parse(*s)
}
func parseOptionalTimestamp(sec *int64) (*time.Time, error) {
if sec == nil {
return nil, nil
}
t := time.Unix(*sec, 0)
return &t, nil
}

View File

@@ -192,6 +192,11 @@ func FromIPLD(node datamodel.Node) (*Token, error) {
return tkn, err
}
type stringAny struct {
Keys []string
Values map[string]datamodel.Node
}
func (t *Token) toIPLD(privKey crypto.PrivKey) (datamodel.Node, error) {
var aud *string
@@ -220,10 +225,7 @@ func (t *Token) toIPLD(privKey crypto.PrivKey) (datamodel.Node, error) {
i++
}
args := struct {
Keys []string
Values map[string]datamodel.Node
}{
args := stringAny{
Keys: argsKey,
Values: t.arguments,
}

View File

@@ -86,6 +86,7 @@ func WithEmptyNonce() Option {
// value of the provided time.Time.
func WithExpiration(exp time.Time) Option {
return func(t *Token) error {
exp = exp.Round(time.Second)
t.expiration = &exp
return nil
@@ -96,7 +97,7 @@ func WithExpiration(exp time.Time) Option {
// Now() plus the given duration.
func WithExpirationIn(exp time.Duration) Option {
return func(t *Token) error {
expTime := time.Now().Add(exp)
expTime := time.Now().Add(exp).Round(time.Minute)
t.expiration = &expTime
return nil

View File

@@ -7,7 +7,6 @@ import (
"github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/datamodel"
"github.com/ipld/go-ipld-prime/node/bindnode"
"github.com/ipld/go-ipld-prime/schema"
@@ -46,7 +45,6 @@ func payloadType() schema.Type {
var _ envelope.Tokener = (*tokenPayloadModel)(nil)
// TODO
type tokenPayloadModel struct {
// The DID of the Invoker
Iss string
@@ -58,10 +56,7 @@ type tokenPayloadModel struct {
// The Command
Cmd string
// The Command's Arguments
Args struct {
Keys []string
Values map[string]datamodel.Node
}
Args stringAny
// Delegations that prove the chain of authority
Prf []cid.Cid