@@ -18,13 +18,17 @@ log.error = debug('libp2p:identify:error')
18
18
19
19
const {
20
20
MULTICODEC_IDENTIFY ,
21
+ MULTICODEC_IDENTIFY_LEGACY ,
21
22
MULTICODEC_IDENTIFY_PUSH ,
23
+ MULTICODEC_IDENTIFY_PUSH_LEGACY ,
22
24
AGENT_VERSION ,
23
25
PROTOCOL_VERSION
24
26
} = require ( './consts' )
25
27
26
28
const errCode = require ( 'err-code' )
27
- const { codes } = require ( '../errors' )
29
+ const { messages, codes } = require ( '../errors' )
30
+ const Envelope = require ( '../record-manager/envelope' )
31
+ const PeerRecord = require ( '../record-manager/peer-record' )
28
32
29
33
class IdentifyService {
30
34
/**
@@ -89,11 +93,27 @@ class IdentifyService {
89
93
push ( connections ) {
90
94
const pushes = connections . map ( async connection => {
91
95
try {
92
- const { stream } = await connection . newStream ( MULTICODEC_IDENTIFY_PUSH )
96
+ const { protocol, stream } = await connection . newStream ( [ MULTICODEC_IDENTIFY_PUSH , MULTICODEC_IDENTIFY_PUSH_LEGACY ] )
97
+
98
+ // Handle Legacy
99
+ if ( protocol === MULTICODEC_IDENTIFY_PUSH_LEGACY ) {
100
+ return pipe (
101
+ [ {
102
+ listenAddrs : this . _libp2p . multiaddrs . map ( ( ma ) => ma . buffer ) ,
103
+ protocols : Array . from ( this . _protocols . keys ( ) )
104
+ } ] ,
105
+ pb . encode ( Message ) ,
106
+ stream ,
107
+ consume
108
+ )
109
+ }
110
+
111
+ const envelope = this . _libp2p . recordManager . getPeerRecord ( )
112
+ const signedPeerRecord = envelope . marshal ( )
93
113
94
114
await pipe (
95
115
[ {
96
- listenAddrs : this . _libp2p . multiaddrs . map ( ( ma ) => ma . buffer ) ,
116
+ signedPeerRecord ,
97
117
protocols : Array . from ( this . _protocols . keys ( ) )
98
118
} ] ,
99
119
pb . encode ( Message ) ,
@@ -135,7 +155,7 @@ class IdentifyService {
135
155
* @returns {Promise<void> }
136
156
*/
137
157
async identify ( connection ) {
138
- const { stream } = await connection . newStream ( MULTICODEC_IDENTIFY )
158
+ const { protocol , stream } = await connection . newStream ( [ MULTICODEC_IDENTIFY , MULTICODEC_IDENTIFY_LEGACY ] )
139
159
const [ data ] = await pipe (
140
160
[ ] ,
141
161
stream ,
@@ -160,7 +180,8 @@ class IdentifyService {
160
180
publicKey,
161
181
listenAddrs,
162
182
protocols,
163
- observedAddr
183
+ observedAddr,
184
+ signedPeerRecord
164
185
} = message
165
186
166
187
const id = await PeerId . createFromPubKey ( publicKey )
@@ -172,8 +193,40 @@ class IdentifyService {
172
193
// Get the observedAddr if there is one
173
194
observedAddr = IdentifyService . getCleanMultiaddr ( observedAddr )
174
195
196
+ // LEGACY: differentiate message with SignedPeerRecord
197
+ if ( protocol === MULTICODEC_IDENTIFY_LEGACY ) {
198
+ // Update peers data in PeerStore
199
+ this . peerStore . addressBook . set ( id , listenAddrs . map ( ( addr ) => multiaddr ( addr ) ) )
200
+ this . peerStore . protoBook . set ( id , protocols )
201
+
202
+ // TODO: Track our observed address so that we can score it
203
+ log ( 'received observed address of %s' , observedAddr )
204
+
205
+ return
206
+ }
207
+
208
+ // Open envelope and verify if is authenticated
209
+ let envelope
210
+ try {
211
+ envelope = await Envelope . openAndCertify ( signedPeerRecord , PeerRecord . DOMAIN )
212
+ } catch ( err ) {
213
+ log ( 'received invalid envelope, discard it' )
214
+ throw errCode ( new Error ( messages . ERR_INVALID_ENVELOPE ) , codes . ERR_INVALID_ENVELOPE )
215
+ }
216
+
217
+ // Decode peer record
218
+ let peerRecord
219
+ try {
220
+ peerRecord = await PeerRecord . createFromProtobuf ( envelope . payload )
221
+ } catch ( err ) {
222
+ log ( 'received invalid peer record, discard it' )
223
+ throw errCode ( new Error ( messages . ERR_INVALID_PEER_RECORD ) , codes . ERR_INVALID_PEER_RECORD )
224
+ }
225
+
226
+ // TODO: Store as certified record
227
+
175
228
// Update peers data in PeerStore
176
- this . peerStore . addressBook . set ( id , listenAddrs . map ( ( addr ) => multiaddr ( addr ) ) )
229
+ this . peerStore . addressBook . set ( id , peerRecord . multiaddrs . map ( ( addr ) => multiaddr ( addr ) ) )
177
230
this . peerStore . protoBook . set ( id , protocols )
178
231
this . peerStore . metadataBook . set ( id , 'AgentVersion' , Buffer . from ( message . agentVersion ) )
179
232
@@ -194,16 +247,20 @@ class IdentifyService {
194
247
switch ( protocol ) {
195
248
case MULTICODEC_IDENTIFY :
196
249
return this . _handleIdentify ( { connection, stream } )
250
+ case MULTICODEC_IDENTIFY_LEGACY :
251
+ return this . _handleIdentifyLegacy ( { connection, stream } )
197
252
case MULTICODEC_IDENTIFY_PUSH :
198
253
return this . _handlePush ( { connection, stream } )
254
+ case MULTICODEC_IDENTIFY_PUSH_LEGACY :
255
+ return this . _handlePushLegacy ( { connection, stream } )
199
256
default :
200
257
log . error ( 'cannot handle unknown protocol %s' , protocol )
201
258
}
202
259
}
203
260
204
261
/**
205
- * Sends the `Identify` response to the requesting peer over the
206
- * given `connection`
262
+ * Sends the `Identify` response with the Signed Peer Record
263
+ * to the requesting peer over the given `connection`
207
264
* @private
208
265
* @param {object } options
209
266
* @param {* } options.stream
@@ -215,6 +272,40 @@ class IdentifyService {
215
272
publicKey = this . peerId . pubKey . bytes
216
273
}
217
274
275
+ const envelope = this . _libp2p . recordManager . getPeerRecord ( )
276
+ const signedPeerRecord = envelope . marshal ( )
277
+
278
+ const message = Message . encode ( {
279
+ protocolVersion : PROTOCOL_VERSION ,
280
+ agentVersion : AGENT_VERSION ,
281
+ publicKey,
282
+ signedPeerRecord,
283
+ observedAddr : connection . remoteAddr . buffer ,
284
+ protocols : Array . from ( this . _protocols . keys ( ) )
285
+ } )
286
+
287
+ pipe (
288
+ [ message ] ,
289
+ lp . encode ( ) ,
290
+ stream ,
291
+ consume
292
+ )
293
+ }
294
+
295
+ /**
296
+ * Sends the `Identify` response with listen addresses (LEGACY)
297
+ * to the requesting peer over the given `connection`
298
+ * @private
299
+ * @param {object } options
300
+ * @param {* } options.stream
301
+ * @param {Connection } options.connection
302
+ */
303
+ _handleIdentifyLegacy ( { connection, stream } ) {
304
+ let publicKey = Buffer . alloc ( 0 )
305
+ if ( this . peerId . pubKey ) {
306
+ publicKey = this . peerId . pubKey . bytes
307
+ }
308
+
218
309
const message = Message . encode ( {
219
310
protocolVersion : PROTOCOL_VERSION ,
220
311
agentVersion : AGENT_VERSION ,
@@ -259,6 +350,63 @@ class IdentifyService {
259
350
return log . error ( 'received invalid message' , err )
260
351
}
261
352
353
+ // Open envelope and verify if is authenticated
354
+ let envelope
355
+ try {
356
+ envelope = await Envelope . openAndCertify ( message . signedPeerRecord , PeerRecord . DOMAIN )
357
+ } catch ( err ) {
358
+ log ( 'received invalid envelope, discard it' )
359
+ throw errCode ( new Error ( messages . ERR_INVALID_ENVELOPE ) , codes . ERR_INVALID_ENVELOPE )
360
+ }
361
+
362
+ // Decode peer record
363
+ let peerRecord
364
+ try {
365
+ peerRecord = await PeerRecord . createFromProtobuf ( envelope . payload )
366
+ } catch ( err ) {
367
+ log ( 'received invalid peer record, discard it' )
368
+ throw errCode ( new Error ( messages . ERR_INVALID_PEER_RECORD ) , codes . ERR_INVALID_PEER_RECORD )
369
+ }
370
+
371
+ // Update peers data in PeerStore
372
+ const id = connection . remotePeer
373
+ try {
374
+ // TODO: Store as certified record
375
+
376
+ this . peerStore . addressBook . set ( id , peerRecord . multiaddrs . map ( ( addr ) => multiaddr ( addr ) ) )
377
+ } catch ( err ) {
378
+ return log . error ( 'received invalid listen addrs' , err )
379
+ }
380
+
381
+ // Update the protocols
382
+ this . peerStore . protoBook . set ( id , message . protocols )
383
+ }
384
+
385
+ /**
386
+ * Reads the Identify Push message from the given `connection`
387
+ * with listen addresses (LEGACY)
388
+ * @private
389
+ * @param {object } options
390
+ * @param {* } options.stream
391
+ * @param {Connection } options.connection
392
+ */
393
+ async _handlePushLegacy ( { connection, stream } ) {
394
+ const [ data ] = await pipe (
395
+ [ ] ,
396
+ stream ,
397
+ lp . decode ( ) ,
398
+ take ( 1 ) ,
399
+ toBuffer ,
400
+ collect
401
+ )
402
+
403
+ let message
404
+ try {
405
+ message = Message . decode ( data )
406
+ } catch ( err ) {
407
+ return log . error ( 'received invalid message' , err )
408
+ }
409
+
262
410
// Update peers data in PeerStore
263
411
const id = connection . remotePeer
264
412
try {
@@ -279,6 +427,8 @@ module.exports.IdentifyService = IdentifyService
279
427
*/
280
428
module . exports . multicodecs = {
281
429
IDENTIFY : MULTICODEC_IDENTIFY ,
282
- IDENTIFY_PUSH : MULTICODEC_IDENTIFY_PUSH
430
+ IDENTIFY_LEGACY : MULTICODEC_IDENTIFY_LEGACY ,
431
+ IDENTIFY_PUSH : MULTICODEC_IDENTIFY_PUSH ,
432
+ IDENTIFY_PUSH_LEGACY : MULTICODEC_IDENTIFY_PUSH_LEGACY
283
433
}
284
434
module . exports . Message = Message
0 commit comments