feat(invocation): ipld unseal to invocation
This commit is contained in:
@@ -23,7 +23,7 @@ import (
|
|||||||
func ExampleNew() {
|
func ExampleNew() {
|
||||||
privKey, iss, sub, cmd, args, prf, meta, err := setupExampleNew()
|
privKey, iss, sub, cmd, args, prf, meta, err := setupExampleNew()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("failed to create setup: %w", err)
|
fmt.Println("failed to create setup:", err.Error())
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -39,21 +39,21 @@ func ExampleNew() {
|
|||||||
invocation.WithExpirationIn(time.Minute),
|
invocation.WithExpirationIn(time.Minute),
|
||||||
invocation.WithoutInvokedAt())
|
invocation.WithoutInvokedAt())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("failed to create invocation: %w", err)
|
fmt.Println("failed to create invocation:", err.Error())
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data, cid, err := inv.ToSealed(privKey)
|
data, cid, err := inv.ToSealed(privKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("failed to seal invocation: %w", err)
|
fmt.Println("failed to seal invocation:", err.Error())
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
json, err := prettyDAGJSON(data)
|
json, err := prettyDAGJSON(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("failed to pretty DAG-JSON: %w", err)
|
fmt.Println("failed to pretty DAG-JSON:", err.Error())
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -139,6 +139,8 @@ func prettyDAGJSON(data []byte) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(jsonData))
|
||||||
|
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
if err := json.Indent(&out, jsonData, "", " "); err != nil {
|
if err := json.Indent(&out, jsonData, "", " "); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -171,14 +173,19 @@ func setupExampleNew() (privKey crypto.PrivKey, iss, sub did.DID, cmd command.Co
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
errs = errors.Join(errs, fmt.Errorf("failed to build headers: %w", err))
|
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) {
|
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, "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.MapEntry(ma, "topics", qp.List(2, func(la datamodel.ListAssembler) {
|
||||||
qp.ListEntry(la, qp.String("authz"))
|
qp.ListEntry(la, qp.String("authz"))
|
||||||
qp.ListEntry(la, qp.String("journal"))
|
qp.ListEntry(la, qp.String("journal"))
|
||||||
}))
|
}))
|
||||||
qp.MapEntry(ma, "draft", qp.Bool(true))
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = errors.Join(errs, fmt.Errorf("failed to build payload: %w", err))
|
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) {
|
tags, err := qp.BuildList(basicnode.Prototype.Any, 3, func(la datamodel.ListAssembler) {
|
||||||
qp.ListEntry(la, qp.String("blog"))
|
qp.ListEntry(la, qp.String("blog"))
|
||||||
qp.ListEntry(la, qp.String("post"))
|
qp.ListEntry(la, qp.String("post"))
|
||||||
|
|||||||
@@ -62,9 +62,8 @@ type Token struct {
|
|||||||
// With the exception of the WithMeta option, all other will overwrite
|
// With the exception of the WithMeta option, all other will overwrite
|
||||||
// the previous contents of their target field.
|
// the previous contents of their target field.
|
||||||
func New(iss, sub did.DID, cmd command.Command, prf []cid.Cid, opts ...Option) (*Token, error) {
|
func New(iss, sub did.DID, cmd command.Command, prf []cid.Cid, opts ...Option) (*Token, error) {
|
||||||
nonce := make([]byte, 12)
|
nonce, err := generateNonce()
|
||||||
|
if err != nil {
|
||||||
if _, err := rand.Read(nonce); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +140,7 @@ func (t *Token) InvokedAt() *time.Time {
|
|||||||
return t.invokedAt
|
return t.invokedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cause returns the (optional)
|
||||||
func (t *Token) Cause() *cid.Cid {
|
func (t *Token) Cause() *cid.Cid {
|
||||||
return t.cause
|
return t.cause
|
||||||
}
|
}
|
||||||
@@ -170,9 +170,41 @@ func (t *Token) validate() error {
|
|||||||
func tokenFromModel(m tokenPayloadModel) (*Token, error) {
|
func tokenFromModel(m tokenPayloadModel) (*Token, error) {
|
||||||
var (
|
var (
|
||||||
tkn Token
|
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
|
return &tkn, nil
|
||||||
}
|
}
|
||||||
@@ -187,3 +219,29 @@ func generateNonce() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return res, nil
|
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
|
return tkn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stringAny struct {
|
||||||
|
Keys []string
|
||||||
|
Values map[string]datamodel.Node
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Token) toIPLD(privKey crypto.PrivKey) (datamodel.Node, error) {
|
func (t *Token) toIPLD(privKey crypto.PrivKey) (datamodel.Node, error) {
|
||||||
var aud *string
|
var aud *string
|
||||||
|
|
||||||
@@ -220,10 +225,7 @@ func (t *Token) toIPLD(privKey crypto.PrivKey) (datamodel.Node, error) {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
args := struct {
|
args := stringAny{
|
||||||
Keys []string
|
|
||||||
Values map[string]datamodel.Node
|
|
||||||
}{
|
|
||||||
Keys: argsKey,
|
Keys: argsKey,
|
||||||
Values: t.arguments,
|
Values: t.arguments,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ func WithEmptyNonce() Option {
|
|||||||
// value of the provided time.Time.
|
// value of the provided time.Time.
|
||||||
func WithExpiration(exp time.Time) Option {
|
func WithExpiration(exp time.Time) Option {
|
||||||
return func(t *Token) error {
|
return func(t *Token) error {
|
||||||
|
exp = exp.Round(time.Second)
|
||||||
t.expiration = &exp
|
t.expiration = &exp
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -96,7 +97,7 @@ func WithExpiration(exp time.Time) Option {
|
|||||||
// Now() plus the given duration.
|
// Now() plus the given duration.
|
||||||
func WithExpirationIn(exp time.Duration) Option {
|
func WithExpirationIn(exp time.Duration) Option {
|
||||||
return func(t *Token) error {
|
return func(t *Token) error {
|
||||||
expTime := time.Now().Add(exp)
|
expTime := time.Now().Add(exp).Round(time.Minute)
|
||||||
t.expiration = &expTime
|
t.expiration = &expTime
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipld/go-ipld-prime"
|
"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/node/bindnode"
|
||||||
"github.com/ipld/go-ipld-prime/schema"
|
"github.com/ipld/go-ipld-prime/schema"
|
||||||
|
|
||||||
@@ -46,7 +45,6 @@ func payloadType() schema.Type {
|
|||||||
|
|
||||||
var _ envelope.Tokener = (*tokenPayloadModel)(nil)
|
var _ envelope.Tokener = (*tokenPayloadModel)(nil)
|
||||||
|
|
||||||
// TODO
|
|
||||||
type tokenPayloadModel struct {
|
type tokenPayloadModel struct {
|
||||||
// The DID of the Invoker
|
// The DID of the Invoker
|
||||||
Iss string
|
Iss string
|
||||||
@@ -58,10 +56,7 @@ type tokenPayloadModel struct {
|
|||||||
// The Command
|
// The Command
|
||||||
Cmd string
|
Cmd string
|
||||||
// The Command's Arguments
|
// The Command's Arguments
|
||||||
Args struct {
|
Args stringAny
|
||||||
Keys []string
|
|
||||||
Values map[string]datamodel.Node
|
|
||||||
}
|
|
||||||
// Delegations that prove the chain of authority
|
// Delegations that prove the chain of authority
|
||||||
Prf []cid.Cid
|
Prf []cid.Cid
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user