-
Notifications
You must be signed in to change notification settings - Fork 445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: exchange signed peer records in identify #682
Changes from 3 commits
5023bce
eb0b020
c2fa11a
d67190b
931b71b
d935021
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,11 @@ | ||
'use strict' | ||
|
||
const { Buffer } = require('buffer') | ||
const debug = require('debug') | ||
const log = debug('libp2p:identify') | ||
log.error = debug('libp2p:identify:error') | ||
|
||
const errCode = require('err-code') | ||
const { Buffer } = require('buffer') | ||
const pb = require('it-protocol-buffers') | ||
const lp = require('it-length-prefixed') | ||
const pipe = require('it-pipe') | ||
|
@@ -13,18 +17,19 @@ const { toBuffer } = require('it-buffer') | |
|
||
const Message = require('./message') | ||
|
||
const log = debug('libp2p:identify') | ||
log.error = debug('libp2p:identify:error') | ||
const Envelope = require('../record/envelope') | ||
const PeerRecord = require('../record/peer-record') | ||
|
||
const { | ||
MULTICODEC_IDENTIFY, | ||
MULTICODEC_IDENTIFY_1_0_0, | ||
MULTICODEC_IDENTIFY_PUSH, | ||
MULTICODEC_IDENTIFY_PUSH_1_0_0, | ||
AGENT_VERSION, | ||
PROTOCOL_VERSION | ||
} = require('./consts') | ||
|
||
const errCode = require('err-code') | ||
const { codes } = require('../errors') | ||
const { messages, codes } = require('../errors') | ||
|
||
class IdentifyService { | ||
/** | ||
|
@@ -79,6 +84,9 @@ class IdentifyService { | |
this._protocols = protocols | ||
|
||
this.handleMessage = this.handleMessage.bind(this) | ||
|
||
// TODO: this should be stored in the certified AddressBook in follow up PR | ||
this._selfRecord = undefined | ||
} | ||
|
||
/** | ||
|
@@ -89,11 +97,13 @@ class IdentifyService { | |
push (connections) { | ||
const pushes = connections.map(async connection => { | ||
try { | ||
const { stream } = await connection.newStream(MULTICODEC_IDENTIFY_PUSH) | ||
const { stream } = await connection.newStream([MULTICODEC_IDENTIFY_PUSH, MULTICODEC_IDENTIFY_PUSH_1_0_0]) | ||
const signedPeerRecord = await this._getSelfPeerRecord() | ||
jacobheun marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
await pipe( | ||
[{ | ||
listenAddrs: this._libp2p.multiaddrs.map((ma) => ma.buffer), | ||
signedPeerRecord, | ||
protocols: Array.from(this._protocols.keys()) | ||
}], | ||
pb.encode(Message), | ||
|
@@ -135,7 +145,7 @@ class IdentifyService { | |
* @returns {Promise<void>} | ||
*/ | ||
async identify (connection) { | ||
const { stream } = await connection.newStream(MULTICODEC_IDENTIFY) | ||
const { protocol, stream } = await connection.newStream([MULTICODEC_IDENTIFY, MULTICODEC_IDENTIFY_1_0_0]) | ||
const [data] = await pipe( | ||
[], | ||
stream, | ||
|
@@ -160,7 +170,8 @@ class IdentifyService { | |
publicKey, | ||
listenAddrs, | ||
protocols, | ||
observedAddr | ||
observedAddr, | ||
signedPeerRecord | ||
} = message | ||
|
||
const id = await PeerId.createFromPubKey(publicKey) | ||
|
@@ -172,8 +183,40 @@ class IdentifyService { | |
// Get the observedAddr if there is one | ||
observedAddr = IdentifyService.getCleanMultiaddr(observedAddr) | ||
|
||
// LEGACY: differentiate message with SignedPeerRecord | ||
if (protocol === MULTICODEC_IDENTIFY_1_0_0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to check the protocol, I'd just check the existence of |
||
// Update peers data in PeerStore | ||
this.peerStore.addressBook.set(id, listenAddrs.map((addr) => multiaddr(addr))) | ||
this.peerStore.protoBook.set(id, protocols) | ||
|
||
// TODO: Track our observed address so that we can score it | ||
log('received observed address of %s', observedAddr) | ||
|
||
return | ||
} | ||
|
||
// Open envelope and verify if is authenticated | ||
let envelope | ||
try { | ||
envelope = await Envelope.openAndCertify(signedPeerRecord, PeerRecord.DOMAIN) | ||
} catch (err) { | ||
log('received invalid envelope, discard it') | ||
throw errCode(new Error(messages.ERR_INVALID_ENVELOPE), codes.ERR_INVALID_ENVELOPE) | ||
} | ||
|
||
// Decode peer record | ||
let peerRecord | ||
try { | ||
peerRecord = await PeerRecord.createFromProtobuf(envelope.payload) | ||
} catch (err) { | ||
log('received invalid peer record, discard it') | ||
throw errCode(new Error(messages.ERR_INVALID_PEER_RECORD), codes.ERR_INVALID_PEER_RECORD) | ||
} | ||
|
||
// TODO: Store as certified record | ||
|
||
// Update peers data in PeerStore | ||
this.peerStore.addressBook.set(id, listenAddrs.map((addr) => multiaddr(addr))) | ||
this.peerStore.addressBook.set(id, peerRecord.multiaddrs.map((addr) => multiaddr(addr))) | ||
this.peerStore.protoBook.set(id, protocols) | ||
|
||
// TODO: Track our observed address so that we can score it | ||
|
@@ -192,17 +235,19 @@ class IdentifyService { | |
handleMessage ({ connection, stream, protocol }) { | ||
switch (protocol) { | ||
case MULTICODEC_IDENTIFY: | ||
case MULTICODEC_IDENTIFY_1_0_0: | ||
return this._handleIdentify({ connection, stream }) | ||
case MULTICODEC_IDENTIFY_PUSH: | ||
case MULTICODEC_IDENTIFY_PUSH_1_0_0: | ||
return this._handlePush({ connection, stream }) | ||
default: | ||
log.error('cannot handle unknown protocol %s', protocol) | ||
} | ||
} | ||
|
||
/** | ||
* Sends the `Identify` response to the requesting peer over the | ||
* given `connection` | ||
* Sends the `Identify` response with the Signed Peer Record | ||
* to the requesting peer over the given `connection` | ||
* @private | ||
* @param {object} options | ||
* @param {*} options.stream | ||
|
@@ -214,11 +259,14 @@ class IdentifyService { | |
publicKey = this.peerId.pubKey.bytes | ||
} | ||
|
||
const signedPeerRecord = await this._getSelfPeerRecord() | ||
|
||
const message = Message.encode({ | ||
protocolVersion: PROTOCOL_VERSION, | ||
agentVersion: AGENT_VERSION, | ||
publicKey, | ||
listenAddrs: this._libp2p.multiaddrs.map((ma) => ma.buffer), | ||
signedPeerRecord, | ||
observedAddr: connection.remoteAddr.buffer, | ||
protocols: Array.from(this._protocols.keys()) | ||
}) | ||
|
@@ -258,17 +306,73 @@ class IdentifyService { | |
return log.error('received invalid message', err) | ||
} | ||
|
||
// Update peers data in PeerStore | ||
const id = connection.remotePeer | ||
|
||
// Legacy | ||
if (!message.signedPeerRecord) { | ||
try { | ||
this.peerStore.addressBook.set(id, message.listenAddrs.map((addr) => multiaddr(addr))) | ||
} catch (err) { | ||
return log.error('received invalid listen addrs', err) | ||
} | ||
|
||
// Update the protocols | ||
this.peerStore.protoBook.set(id, message.protocols) | ||
|
||
return | ||
} | ||
jacobheun marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Open envelope and verify if is authenticated | ||
let envelope | ||
try { | ||
envelope = await Envelope.openAndCertify(message.signedPeerRecord, PeerRecord.DOMAIN) | ||
} catch (err) { | ||
log('received invalid envelope, discard it') | ||
throw errCode(new Error(messages.ERR_INVALID_ENVELOPE), codes.ERR_INVALID_ENVELOPE) | ||
} | ||
|
||
// Decode peer record | ||
let peerRecord | ||
try { | ||
peerRecord = await PeerRecord.createFromProtobuf(envelope.payload) | ||
} catch (err) { | ||
log('received invalid peer record, discard it') | ||
throw errCode(new Error(messages.ERR_INVALID_PEER_RECORD), codes.ERR_INVALID_PEER_RECORD) | ||
} | ||
|
||
// Update peers data in PeerStore | ||
try { | ||
this.peerStore.addressBook.set(id, message.listenAddrs.map((addr) => multiaddr(addr))) | ||
// TODO: Store as certified record | ||
|
||
this.peerStore.addressBook.set(id, peerRecord.multiaddrs.map((addr) => multiaddr(addr))) | ||
} catch (err) { | ||
return log.error('received invalid listen addrs', err) | ||
} | ||
|
||
// Update the protocols | ||
this.peerStore.protoBook.set(id, message.protocols) | ||
} | ||
|
||
/** | ||
* Get self signed peer record raw envelope. | ||
* @return {Buffer} | ||
*/ | ||
async _getSelfPeerRecord () { | ||
jacobheun marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// TODO: Verify if updated | ||
jacobheun marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (this._selfRecord) { | ||
return this._selfRecord | ||
} | ||
|
||
const peerRecord = new PeerRecord({ | ||
peerId: this.peerId, | ||
multiaddrs: this._libp2p.multiaddrs | ||
}) | ||
const envelope = await Envelope.seal(peerRecord, this.peerId) | ||
|
||
this._selfRecord = envelope.marshal() | ||
|
||
return this._selfRecord | ||
} | ||
} | ||
|
||
module.exports.IdentifyService = IdentifyService | ||
|
@@ -278,6 +382,8 @@ module.exports.IdentifyService = IdentifyService | |
*/ | ||
module.exports.multicodecs = { | ||
IDENTIFY: MULTICODEC_IDENTIFY, | ||
IDENTIFY_PUSH: MULTICODEC_IDENTIFY_PUSH | ||
IDENTIFY_1_0_0: MULTICODEC_IDENTIFY_1_0_0, | ||
IDENTIFY_PUSH: MULTICODEC_IDENTIFY_PUSH, | ||
IDENTIFY_PUSH_1_0_0: MULTICODEC_IDENTIFY_PUSH_1_0_0 | ||
} | ||
module.exports.Message = Message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where are the versions listed, I was having trouble finding the updates. Is this in the specs repo or in go-libp2p?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit added them: libp2p/go-libp2p@077a818#diff-98be6dba669aa4123b7ef190fe7113e8
However, now that I looked further, the same protocol is now being used and go reverted this change per libp2p/go-libp2p#907 (comment)
I am doing the same