Skip to content

Commit 8cdf7ce

Browse files
committed
refactor: use dag-cbor for signatures
1 parent ab55164 commit 8cdf7ce

File tree

1 file changed

+50
-89
lines changed

1 file changed

+50
-89
lines changed

Diff for: routing/http/types/record_announcement.go

+50-89
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import (
77
"fmt"
88
"time"
99

10+
"github.com/ipfs/boxo/routing/http/internal/drjson"
1011
"github.com/ipfs/boxo/util"
1112
"github.com/ipfs/go-cid"
1213
"github.com/ipld/go-ipld-prime"
13-
"github.com/ipld/go-ipld-prime/codec/dagjson"
14+
"github.com/ipld/go-ipld-prime/codec/dagcbor"
1415
"github.com/ipld/go-ipld-prime/datamodel"
1516
"github.com/ipld/go-ipld-prime/node/basicnode"
1617
"github.com/libp2p/go-libp2p/core/crypto"
@@ -51,9 +52,7 @@ type AnnouncementPayload struct {
5152
Metadata string
5253
}
5354

54-
// MarshalJSON marshals the [AnnouncementPayload] into a canonical DAG-JSON
55-
// representation of the payload.
56-
func (ap AnnouncementPayload) MarshalJSON() ([]byte, error) {
55+
func (ap AnnouncementPayload) asDagCbor() ([]byte, error) {
5756
m := make(map[string]ipld.Node)
5857
var err error
5958

@@ -112,29 +111,51 @@ func (ap AnnouncementPayload) MarshalJSON() ([]byte, error) {
112111
// Encode it with the DAG-JSON encoder, which automatically sorts the fields
113112
// in a deterministic manner.
114113
var b bytes.Buffer
115-
err = dagjson.Encode(nd, &b)
114+
err = dagcbor.Encode(nd, &b)
116115
if err != nil {
117116
return nil, err
118117
}
119118

120119
return b.Bytes(), nil
121120
}
122121

122+
type announcementPayloadHelper struct {
123+
CID string `json:",omitempty"`
124+
ID *peer.ID `json:",omitempty"`
125+
Scope AnnouncementScope `json:",omitempty"`
126+
Timestamp string `json:",omitempty"`
127+
TTL int64 `json:",omitempty"`
128+
Addrs []Multiaddr `json:",omitempty"`
129+
Protocols []string `json:",omitempty"`
130+
Metadata string `json:",omitempty"`
131+
}
132+
133+
func (ap AnnouncementPayload) MarshalJSON() ([]byte, error) {
134+
v := announcementPayloadHelper{
135+
ID: ap.ID,
136+
Scope: ap.Scope,
137+
Addrs: ap.Addrs,
138+
Protocols: ap.Protocols,
139+
Metadata: ap.Metadata,
140+
}
141+
142+
if ap.CID.Defined() {
143+
v.CID = ap.CID.String()
144+
}
145+
146+
if !ap.Timestamp.IsZero() {
147+
v.Timestamp = util.FormatRFC3339(ap.Timestamp)
148+
}
149+
150+
if ap.TTL != 0 {
151+
v.TTL = ap.TTL.Milliseconds()
152+
}
153+
154+
return drjson.MarshalJSONBytes(v)
155+
}
156+
123157
func (ap *AnnouncementPayload) UnmarshalJSON(b []byte) error {
124-
// TODO: this is the "simple" way of decoding the payload. I am assuming
125-
// we want to encode everything using strings (except for TTL). If we decide
126-
// to use DAG-JSON native types (e.g. Bytes), we have to convert this to IPLD code
127-
// in order to convert things properly.
128-
v := struct {
129-
CID string
130-
Scope AnnouncementScope
131-
Timestamp string
132-
TTL int64
133-
ID *peer.ID
134-
Addrs []Multiaddr
135-
Protocols []string
136-
Metadata string
137-
}{}
158+
v := announcementPayloadHelper{}
138159
err := json.Unmarshal(b, &v)
139160
if err != nil {
140161
return err
@@ -173,76 +194,20 @@ func (ap *AnnouncementPayload) UnmarshalJSON(b []byte) error {
173194

174195
// AnnouncementRecord is a [Record] of [SchemaAnnouncement].
175196
type AnnouncementRecord struct {
176-
Schema string
177-
Error string
178-
Payload AnnouncementPayload
179-
RawPayload json.RawMessage
180-
Signature string
197+
Schema string
198+
Error string `json:",omitempty"`
199+
Payload AnnouncementPayload
200+
Signature string `json:",omitempty"`
181201
}
182202

183203
func (ar *AnnouncementRecord) GetSchema() string {
184204
return ar.Schema
185205
}
186206

187-
func (ar AnnouncementRecord) MarshalJSON() ([]byte, error) {
188-
if ar.RawPayload == nil {
189-
// This happens when [AnnouncementRecord] is used for response. In that
190-
// case it is not signed. Therefore, the RawPayload is not yet set.
191-
err := ar.setRawPayload()
192-
if err != nil {
193-
return nil, err
194-
}
195-
}
196-
197-
v := struct {
198-
Schema string
199-
Error string `json:"Error,omitempty"`
200-
Payload json.RawMessage
201-
Signature string `json:"Signature,omitempty"`
202-
}{
203-
Schema: ar.Schema,
204-
Error: ar.Error,
205-
Payload: ar.RawPayload,
206-
Signature: ar.Signature,
207-
}
208-
209-
return json.Marshal(v)
210-
}
211-
212-
func (ar *AnnouncementRecord) UnmarshalJSON(b []byte) error {
213-
// Unmarshal all known fields and assign them.
214-
v := struct {
215-
Schema string
216-
Error string
217-
Payload json.RawMessage
218-
Signature string
219-
}{}
220-
err := json.Unmarshal(b, &v)
221-
if err != nil {
222-
return err
223-
}
224-
225-
ar.Schema = v.Schema
226-
ar.Error = v.Error
227-
ar.RawPayload = v.Payload
228-
ar.Signature = v.Signature
229-
return (&ar.Payload).UnmarshalJSON(ar.RawPayload)
230-
}
231-
232207
func (ar AnnouncementRecord) IsSigned() bool {
233208
return ar.Signature != ""
234209
}
235210

236-
func (ar *AnnouncementRecord) setRawPayload() error {
237-
bytes, err := ar.Payload.MarshalJSON()
238-
if err != nil {
239-
return err
240-
}
241-
242-
ar.RawPayload = bytes
243-
return nil
244-
}
245-
246211
func (ar *AnnouncementRecord) Sign(peerID peer.ID, key crypto.PrivKey) error {
247212
if ar.IsSigned() {
248213
return errors.New("already signed")
@@ -260,13 +225,13 @@ func (ar *AnnouncementRecord) Sign(peerID peer.ID, key crypto.PrivKey) error {
260225
return errors.New("not the correct signing key")
261226
}
262227

263-
err = ar.setRawPayload()
228+
data, err := ar.Payload.asDagCbor()
264229
if err != nil {
265230
return err
266231
}
267232

268233
dataForSig := []byte(announcementSignaturePrefix)
269-
dataForSig = append(dataForSig, ar.RawPayload...)
234+
dataForSig = append(dataForSig, data...)
270235

271236
rawSignature, err := key.Sign(dataForSig)
272237
if err != nil {
@@ -291,13 +256,9 @@ func (ar *AnnouncementRecord) Verify() error {
291256
return errors.New("peer ID must be specified")
292257
}
293258

294-
// note that we only generate and set the payload if it hasn't already been set
295-
// to allow for passing through the payload untouched if it is already provided
296-
if ar.RawPayload == nil {
297-
err := ar.setRawPayload()
298-
if err != nil {
299-
return err
300-
}
259+
data, err := ar.Payload.asDagCbor()
260+
if err != nil {
261+
return err
301262
}
302263

303264
pk, err := ar.Payload.ID.ExtractPublicKey()
@@ -311,7 +272,7 @@ func (ar *AnnouncementRecord) Verify() error {
311272
}
312273

313274
dataForSig := []byte(announcementSignaturePrefix)
314-
dataForSig = append(dataForSig, ar.RawPayload...)
275+
dataForSig = append(dataForSig, data...)
315276

316277
ok, err := pk.Verify(dataForSig, sigBytes)
317278
if err != nil {

0 commit comments

Comments
 (0)