diff --git a/delegation/ipld.go b/delegation/ipld.go index d99c613..05198ca 100644 --- a/delegation/ipld.go +++ b/delegation/ipld.go @@ -16,8 +16,8 @@ import ( // Encode marshals a View to the format specified by the provided // codec.Encoder. -func (d *View) Encode(privKey crypto.PrivKey, encFn codec.Encoder) ([]byte, error) { - node, err := d.ToIPLD(privKey) +func (t *Token) Encode(privKey crypto.PrivKey, encFn codec.Encoder) ([]byte, error) { + node, err := t.ToIPLD(privKey) if err != nil { return nil, err } @@ -26,8 +26,8 @@ func (d *View) Encode(privKey crypto.PrivKey, encFn codec.Encoder) ([]byte, erro } // EncodeWriter is the same as Encode but accepts an io.Writer. -func (d *View) EncodeWriter(w io.Writer, privKey crypto.PrivKey, encFn codec.Encoder) error { - node, err := d.ToIPLD(privKey) +func (t *Token) EncodeWriter(w io.Writer, privKey crypto.PrivKey, encFn codec.Encoder) error { + node, err := t.ToIPLD(privKey) if err != nil { return err } @@ -36,68 +36,68 @@ func (d *View) EncodeWriter(w io.Writer, privKey crypto.PrivKey, encFn codec.Enc } // ToDagCbor marshals the View to the DAG-CBOR format. -func (d *View) ToDagCbor(privKey crypto.PrivKey) ([]byte, error) { - return d.Encode(privKey, dagcbor.Encode) +func (t *Token) ToDagCbor(privKey crypto.PrivKey) ([]byte, error) { + return t.Encode(privKey, dagcbor.Encode) } // ToDagCborWriter is the same as ToDagCbor but it accepts an io.Writer. -func (d *View) ToDagCborWriter(w io.Writer, privKey crypto.PrivKey) error { - return d.EncodeWriter(w, privKey, dagcbor.Encode) +func (t *Token) ToDagCborWriter(w io.Writer, privKey crypto.PrivKey) error { + return t.EncodeWriter(w, privKey, dagcbor.Encode) } // ToDagJson marshals the View to the DAG-JSON format. -func (d *View) ToDagJson(privKey crypto.PrivKey) ([]byte, error) { - return d.Encode(privKey, dagjson.Encode) +func (t *Token) ToDagJson(privKey crypto.PrivKey) ([]byte, error) { + return t.Encode(privKey, dagjson.Encode) } // ToDagJsonWriter is the same as ToDagJson but it accepts an io.Writer. -func (d *View) ToDagJsonWriter(w io.Writer, privKey crypto.PrivKey) error { - return d.EncodeWriter(w, privKey, dagjson.Encode) +func (t *Token) ToDagJsonWriter(w io.Writer, privKey crypto.PrivKey) error { + return t.EncodeWriter(w, privKey, dagjson.Encode) } // ToIPLD wraps the View in an IPLD datamodel.Node. -func (d *View) ToIPLD(privKey crypto.PrivKey) (datamodel.Node, error) { +func (t *Token) ToIPLD(privKey crypto.PrivKey) (datamodel.Node, error) { var sub *string - if d.Subject != did.Undef { - s := d.Subject.String() + if t.subject != did.Undef { + s := t.subject.String() sub = &s } - pol, err := d.Policy.ToIPLD() + pol, err := t.policy.ToIPLD() if err != nil { return nil, err } - metaKeys := make([]string, len(d.Meta)) + metaKeys := make([]string, len(t.meta)) i := 0 - for k := range d.Meta { + for k := range t.meta { metaKeys[i] = k i++ } var nbf *int64 - if d.NotBefore != nil { - u := d.NotBefore.Unix() + if t.notBefore != nil { + u := t.notBefore.Unix() nbf = &u } var exp *int64 - if d.Expiration != nil { - u := d.Expiration.Unix() + if t.expiration != nil { + u := t.expiration.Unix() exp = &u } model := &tokenPayloadModel{ - Iss: d.Issuer.String(), - Aud: d.Audience.String(), + Iss: t.issuer.String(), + Aud: t.audience.String(), Sub: sub, - Cmd: d.Command.String(), + Cmd: t.command.String(), Pol: pol, - Nonce: d.Nonce, + Nonce: t.nonce, Meta: metaModel{ Keys: metaKeys, - Values: d.Meta, + Values: t.meta, }, Nbf: nbf, Exp: exp, @@ -111,7 +111,7 @@ func (d *View) ToIPLD(privKey crypto.PrivKey) (datamodel.Node, error) { // // An error is returned if the conversion fails, or if the resulting // View is invalid. -func Decode(b []byte, decFn codec.Decoder) (*View, error) { +func Decode(b []byte, decFn codec.Decoder) (*Token, error) { node, err := ipld.Decode(b, decFn) if err != nil { return nil, err @@ -120,7 +120,7 @@ func Decode(b []byte, decFn codec.Decoder) (*View, error) { } // DecodeReader is the same as Decode, but accept an io.Reader. -func DecodeReader(r io.Reader, decFn codec.Decoder) (*View, error) { +func DecodeReader(r io.Reader, decFn codec.Decoder) (*Token, error) { node, err := ipld.DecodeStreaming(r, decFn) if err != nil { return nil, err @@ -132,12 +132,12 @@ func DecodeReader(r io.Reader, decFn codec.Decoder) (*View, error) { // // An error is returned if the conversion fails, or if the resulting // View is invalid. -func FromDagCbor(data []byte) (*View, error) { +func FromDagCbor(data []byte) (*Token, error) { return Decode(data, dagcbor.Decode) } // FromDagCborReader is the same as FromDagCbor, but accept an io.Reader. -func FromDagCborReader(r io.Reader) (*View, error) { +func FromDagCborReader(r io.Reader) (*Token, error) { return DecodeReader(r, dagcbor.Decode) } @@ -145,12 +145,12 @@ func FromDagCborReader(r io.Reader) (*View, error) { // // An error is returned if the conversion fails, or if the resulting // View is invalid. -func FromDagJson(data []byte) (*View, error) { +func FromDagJson(data []byte) (*Token, error) { return Decode(data, dagjson.Decode) } // FromDagJsonReader is the same as FromDagJson, but accept an io.Reader. -func FromDagJsonReader(r io.Reader) (*View, error) { +func FromDagJsonReader(r io.Reader) (*Token, error) { return DecodeReader(r, dagjson.Decode) } @@ -158,7 +158,7 @@ func FromDagJsonReader(r io.Reader) (*View, error) { // // An error is returned if the conversion fails, or if the resulting // View is invalid. -func FromIPLD(node datamodel.Node) (*View, error) { +func FromIPLD(node datamodel.Node) (*Token, error) { tkn, _, err := envelope.FromIPLD[*tokenPayloadModel](node) // TODO add CID to view if err != nil { return nil, err diff --git a/delegation/view.go b/delegation/view.go index 97dc8b6..9d96b17 100644 --- a/delegation/view.go +++ b/delegation/view.go @@ -11,58 +11,107 @@ import ( "github.com/ucan-wg/go-ucan/did" ) -type View struct { +type Token struct { // Issuer DID (sender) - Issuer did.DID + issuer did.DID // Audience DID (receiver) - Audience did.DID + audience did.DID // Principal that the chain is about (the Subject) - Subject did.DID + subject did.DID // The Command to eventually invoke - Command *command.Command + command *command.Command // The delegation policy - Policy policy.Policy + policy policy.Policy // A unique, random nonce - Nonce []byte + nonce []byte // Arbitrary Metadata - Meta map[string]datamodel.Node + meta map[string]datamodel.Node // "Not before" UTC Unix Timestamp in seconds (valid from), 53-bits integer - NotBefore *time.Time + notBefore *time.Time // The timestamp at which the Invocation becomes invalid - Expiration *time.Time + expiration *time.Time +} + +// Issuer returns the did.DID representing the Token's issuer. +func (t *Token) Issuer() did.DID { + return t.issuer +} + +// Audience returns the did.DID representing the Token's audience. +func (t *Token) Audience() did.DID { + return t.audience +} + +// Subject returns the did.DID representing the Token's subject. +// +// This field may be did.Undef for delegations that are [Powerlined] but +// must be equal to the value returned by the Issuer method for root +// tokens. +func (t *Token) Subject() did.DID { + return t.subject +} + +// Command returns the capability's command.Command. +func (t *Token) Command() *command.Command { + return t.command +} + +// Policy returns the capability's policy.Policy. +func (t *Token) Policy() policy.Policy { + return t.policy +} + +// Nonce returns the random Nonce encapsulated in this Token. +func (t *Token) Nonce() []byte { + return t.nonce +} + +// Meta returns the Token's metadata. +func (t *Token) Meta() map[string]datamodel.Node { + return t.meta +} + +// NotBefore returns the time at which the Token becomes "active". +func (t *Token) NotBefore() *time.Time { + return t.notBefore +} + +// Expiration returns the time at which the Token expires. +func (t *Token) Expiration() *time.Time { + return t.expiration } // viewFromModel build a decoded view of the raw IPLD data. // This function also serves as validation. -func viewFromModel(m tokenPayloadModel) (*View, error) { - var view View +func viewFromModel(m tokenPayloadModel) (*Token, error) { + var view Token var err error - view.Issuer, err = did.Parse(m.Iss) + view.issuer, err = did.Parse(m.Iss) if err != nil { return nil, fmt.Errorf("parse iss: %w", err) } - view.Audience, err = did.Parse(m.Aud) + view.audience, err = did.Parse(m.Aud) if err != nil { return nil, fmt.Errorf("parse audience: %w", err) } if m.Sub != nil { - view.Subject, err = did.Parse(*m.Sub) + view.subject, err = did.Parse(*m.Sub) if err != nil { return nil, fmt.Errorf("parse subject: %w", err) } } else { - view.Subject = did.Undef + view.subject = did.Undef } - view.Command, err = command.Parse(m.Cmd) + view.command, err = command.Parse(m.Cmd) if err != nil { return nil, fmt.Errorf("parse command: %w", err) } - view.Policy, err = policy.FromIPLD(m.Pol) + view.policy, err = policy.FromIPLD(m.Pol) if err != nil { return nil, fmt.Errorf("parse policy: %w", err) } @@ -70,19 +119,19 @@ func viewFromModel(m tokenPayloadModel) (*View, error) { if len(m.Nonce) == 0 { return nil, fmt.Errorf("nonce is required") } - view.Nonce = m.Nonce + view.nonce = m.Nonce // TODO: copy? - view.Meta = m.Meta.Values + view.meta = m.Meta.Values if m.Nbf != nil { t := time.Unix(*m.Nbf, 0) - view.NotBefore = &t + view.notBefore = &t } if m.Exp != nil { t := time.Unix(*m.Exp, 0) - view.Expiration = &t + view.expiration = &t } return &view, nil