Skip to content

Commit 9e4104d

Browse files
committed
feat: more dag-json marshaling
1 parent f418a02 commit 9e4104d

3 files changed

Lines changed: 99 additions & 10 deletions

File tree

ucan/delegation/delegation.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ func (d *Delegation) Metadata() ipld.Map[string, ipld.Any] {
8080
return d.model.SigPayload.TokenPayload1_0_0_rc1.Meta
8181
}
8282

83+
// The datamodel this delegation is built from.
84+
func (d *Delegation) Model() *ddm.EnvelopeModel {
85+
return d.model
86+
}
87+
8388
// Nonce helps prevent replay attacks and ensures a unique CID per delegation.
8489
//
8590
// https://github.com/ucan-wg/spec/blob/main/README.md#nonce
@@ -155,12 +160,53 @@ func (d *Delegation) UnmarshalCBOR(r io.Reader) error {
155160
return nil
156161
}
157162

163+
func (d *Delegation) MarshalDagJSON(w io.Writer) error {
164+
return d.Model().MarshalDagJSON(w)
165+
}
166+
167+
func (d *Delegation) UnmarshalDagJSON(r io.Reader) error {
168+
*d = Delegation{}
169+
model := ddm.EnvelopeModel{}
170+
err := model.UnmarshalDagJSON(r)
171+
if err != nil {
172+
return fmt.Errorf("unmarshaling delegation envelope JSON: %w", err)
173+
}
174+
if model.SigPayload.TokenPayload1_0_0_rc1 == nil {
175+
return errors.New("invalid or unsupported delegation token payload")
176+
}
177+
header, err := varsig.Decode(model.SigPayload.Header)
178+
if err != nil {
179+
return fmt.Errorf("decoding varsig header: %w", err)
180+
}
181+
sig := signature.NewSignature(header, model.Signature)
182+
// marshal to CBOR so we can calculate canonical CID
183+
var w bytes.Buffer
184+
err = model.MarshalCBOR(&w)
185+
if err != nil {
186+
return fmt.Errorf("marshaling to CBOR: %w", err)
187+
}
188+
root, err := cid.V1Builder{
189+
Codec: dagcbor.Code,
190+
MhType: multihash.SHA2_256,
191+
}.Sum(w.Bytes())
192+
if err != nil {
193+
return fmt.Errorf("hashing delegation bytes: %w", err)
194+
}
195+
d.link = root
196+
d.bytes = w.Bytes()
197+
d.sig = sig
198+
d.model = &model
199+
return nil
200+
}
201+
158202
var _ ucan.Delegation = (*Delegation)(nil)
159203

204+
// Encode delegation to CBOR.
160205
func Encode(dlg ucan.Delegation) ([]byte, error) {
161206
return dlg.Bytes(), nil
162207
}
163208

209+
// Encode delegation from CBOR.
164210
func Decode(b []byte) (*Delegation, error) {
165211
d := Delegation{}
166212
err := d.UnmarshalCBOR(bytes.NewReader(b))

ucan/invocation/invocation.go

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"github.com/alanshaw/ucantone/varsig/common"
2121
cid "github.com/ipfs/go-cid"
2222
multihash "github.com/multiformats/go-multihash/core"
23-
cbg "github.com/whyrusleeping/cbor-gen"
2423
)
2524

2625
// UCAN Invocation defines a format for expressing the intention to execute
@@ -200,12 +199,63 @@ func (inv *Invocation) UnmarshalCBOR(r io.Reader) error {
200199
return nil
201200
}
202201

202+
func (inv *Invocation) MarshalDagJSON(w io.Writer) error {
203+
return inv.Model().MarshalDagJSON(w)
204+
}
205+
206+
func (inv *Invocation) UnmarshalDagJSON(r io.Reader) error {
207+
*inv = Invocation{}
208+
model := idm.EnvelopeModel{}
209+
err := model.UnmarshalDagJSON(r)
210+
if err != nil {
211+
return fmt.Errorf("unmarshaling invocation envelope JSON: %w", err)
212+
}
213+
if model.SigPayload.TokenPayload1_0_0_rc1 == nil {
214+
return errors.New("invalid or unsupported invocation token payload")
215+
}
216+
header, err := varsig.Decode(model.SigPayload.Header)
217+
if err != nil {
218+
return fmt.Errorf("decoding varsig header: %w", err)
219+
}
220+
sig := signature.NewSignature(header, model.Signature)
221+
task, err := NewTask(
222+
model.SigPayload.TokenPayload1_0_0_rc1.Sub,
223+
model.SigPayload.TokenPayload1_0_0_rc1.Cmd,
224+
model.SigPayload.TokenPayload1_0_0_rc1.Args,
225+
model.SigPayload.TokenPayload1_0_0_rc1.Nonce,
226+
)
227+
if err != nil {
228+
return fmt.Errorf("creating new task: %w", err)
229+
}
230+
// marshal to CBOR so we can calculate canonical CID
231+
var w bytes.Buffer
232+
err = model.MarshalCBOR(&w)
233+
if err != nil {
234+
return fmt.Errorf("marshaling to CBOR: %w", err)
235+
}
236+
root, err := cid.V1Builder{
237+
Codec: dagcbor.Code,
238+
MhType: multihash.SHA2_256,
239+
}.Sum(w.Bytes())
240+
if err != nil {
241+
return fmt.Errorf("hashing invocation bytes: %w", err)
242+
}
243+
inv.link = root
244+
inv.bytes = w.Bytes()
245+
inv.sig = sig
246+
inv.model = &model
247+
inv.task = task
248+
return nil
249+
}
250+
203251
var _ ucan.Invocation = (*Invocation)(nil)
204252

253+
// Encode invocation to CBOR.
205254
func Encode(inv ucan.Invocation) ([]byte, error) {
206255
return inv.Bytes(), nil
207256
}
208257

258+
// Decode invocation from CBOR.
209259
func Decode(b []byte) (*Invocation, error) {
210260
inv := Invocation{}
211261
err := inv.UnmarshalCBOR(bytes.NewReader(b))
@@ -343,15 +393,6 @@ func VerifySignature(inv ucan.Invocation, verifier ucan.Verifier) (bool, error)
343393
aud = &a
344394
}
345395

346-
var args cbg.Deferred
347-
argsMap := datamodel.NewMap(datamodel.WithEntries(inv.Arguments().All()))
348-
var argsBuf bytes.Buffer
349-
err := argsMap.MarshalCBOR(&argsBuf)
350-
if err != nil {
351-
return false, fmt.Errorf("marshaling arguments CBOR: %w", err)
352-
}
353-
args.Raw = argsBuf.Bytes()
354-
355396
var meta *datamodel.Map
356397
if inv.Metadata() != nil {
357398
meta = datamodel.NewMap(datamodel.WithEntries(inv.Metadata().All()))

ucan/receipt/receipt.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,12 @@ func (rcpt *Receipt) UnmarshalCBOR(r io.Reader) error {
8282

8383
var _ ucan.Receipt = (*Receipt)(nil)
8484

85+
// Encode receipt to CBOR.
8586
func Encode(rcpt ucan.Receipt) ([]byte, error) {
8687
return rcpt.Bytes(), nil
8788
}
8889

90+
// Decode receipt from CBOR.
8991
func Decode(b []byte) (*Receipt, error) {
9092
rcpt := Receipt{}
9193
err := rcpt.UnmarshalCBOR(bytes.NewReader(b))

0 commit comments

Comments
 (0)