feat(invocation): ipld unseal to invocation
This commit is contained in:
@@ -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"))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user