diff --git a/src/errors.js b/src/errors.js index 079e5c89cd..18e600c6dc 100644 --- a/src/errors.js +++ b/src/errors.js @@ -3,9 +3,7 @@ exports.messages = { NOT_STARTED_YET: 'The libp2p node is not started yet', DHT_DISABLED: 'DHT is not available', - CONN_ENCRYPTION_REQUIRED: 'At least one connection encryption module is required', - ERR_INVALID_ENVELOPE: 'Invalid envelope received', - ERR_INVALID_PEER_RECORD: 'Invalid peer record received' + CONN_ENCRYPTION_REQUIRED: 'At least one connection encryption module is required' } exports.codes = { @@ -22,8 +20,6 @@ exports.codes = { ERR_DUPLICATE_TRANSPORT: 'ERR_DUPLICATE_TRANSPORT', ERR_ENCRYPTION_FAILED: 'ERR_ENCRYPTION_FAILED', ERR_HOP_REQUEST_FAILED: 'ERR_HOP_REQUEST_FAILED', - ERR_INVALID_ENVELOPE: 'ERR_INVALID_ENVELOPE', - ERR_INVALID_PEER_RECORD: 'ERR_INVALID_PEER_RECORD', ERR_INVALID_KEY: 'ERR_INVALID_KEY', ERR_INVALID_MESSAGE: 'ERR_INVALID_MESSAGE', ERR_INVALID_PARAMETERS: 'ERR_INVALID_PARAMETERS', diff --git a/src/identify/consts.js b/src/identify/consts.js index 5956ebb08b..58ec077faa 100644 --- a/src/identify/consts.js +++ b/src/identify/consts.js @@ -4,9 +4,5 @@ const libp2pVersion = require('../../package.json').version module.exports.PROTOCOL_VERSION = 'ipfs/0.1.0' module.exports.AGENT_VERSION = `js-libp2p/${libp2pVersion}` -module.exports.MULTICODEC_IDENTIFY = '/p2p/id/1.1.0' -module.exports.MULTICODEC_IDENTIFY_PUSH = '/p2p/id/push/1.1.0' - -// Legacy -module.exports.MULTICODEC_IDENTIFY_1_0_0 = '/ipfs/id/1.0.0' -module.exports.MULTICODEC_IDENTIFY_PUSH_1_0_0 = '/ipfs/id/push/1.0.0' +module.exports.MULTICODEC_IDENTIFY = '/ipfs/id/1.0.0' +module.exports.MULTICODEC_IDENTIFY_PUSH = '/ipfs/id/push/1.0.0' diff --git a/src/identify/index.js b/src/identify/index.js index ac5e79ec71..b4c65c0e62 100644 --- a/src/identify/index.js +++ b/src/identify/index.js @@ -22,14 +22,12 @@ 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 { messages, codes } = require('../errors') +const { codes } = require('../errors') class IdentifyService { /** @@ -97,7 +95,7 @@ class IdentifyService { push (connections) { const pushes = connections.map(async connection => { try { - const { stream } = await connection.newStream([MULTICODEC_IDENTIFY_PUSH, MULTICODEC_IDENTIFY_PUSH_1_0_0]) + const { stream } = await connection.newStream(MULTICODEC_IDENTIFY_PUSH) const signedPeerRecord = await this._getSelfPeerRecord() await pipe( @@ -145,7 +143,7 @@ class IdentifyService { * @returns {Promise} */ async identify (connection) { - const { protocol, stream } = await connection.newStream([MULTICODEC_IDENTIFY, MULTICODEC_IDENTIFY_1_0_0]) + const { stream } = await connection.newStream(MULTICODEC_IDENTIFY) const [data] = await pipe( [], stream, @@ -183,40 +181,26 @@ 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) { - // Update peers data in PeerStore - this.peerStore.addressBook.set(id, listenAddrs.map((addr) => multiaddr(addr))) - this.peerStore.protoBook.set(id, protocols) + let addresses - // 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) + const envelope = await Envelope.openAndCertify(signedPeerRecord, PeerRecord.DOMAIN) + const peerRecord = await PeerRecord.createFromProtobuf(envelope.payload) + + addresses = peerRecord.multiaddrs } catch (err) { - log('received invalid envelope, discard it') - throw errCode(new Error(messages.ERR_INVALID_ENVELOPE), codes.ERR_INVALID_ENVELOPE) + log('received invalid envelope, discard it and fallback to listenAddrs is available') + // Try Legacy + addresses = listenAddrs } - // Decode peer record - let peerRecord + // Update peers data in PeerStore try { - peerRecord = await PeerRecord.createFromProtobuf(envelope.payload) + this.peerStore.addressBook.set(id, addresses.map((addr) => multiaddr(addr))) } catch (err) { - log('received invalid peer record, discard it') - throw errCode(new Error(messages.ERR_INVALID_PEER_RECORD), codes.ERR_INVALID_PEER_RECORD) + log.error('received invalid addrs', err) } - // TODO: Store as certified record - - // Update peers data in PeerStore - this.peerStore.addressBook.set(id, peerRecord.multiaddrs.map((addr) => multiaddr(addr))) this.peerStore.protoBook.set(id, protocols) this.peerStore.metadataBook.set(id, 'AgentVersion', Buffer.from(message.agentVersion)) @@ -236,10 +220,8 @@ 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) @@ -309,45 +291,23 @@ class IdentifyService { 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 - } + let addresses - // 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) - } + const envelope = await Envelope.openAndCertify(message.signedPeerRecord, PeerRecord.DOMAIN) + const peerRecord = await PeerRecord.createFromProtobuf(envelope.payload) - // Decode peer record - let peerRecord - try { - peerRecord = await PeerRecord.createFromProtobuf(envelope.payload) + addresses = peerRecord.multiaddrs } catch (err) { - log('received invalid peer record, discard it') - throw errCode(new Error(messages.ERR_INVALID_PEER_RECORD), codes.ERR_INVALID_PEER_RECORD) + log('received invalid envelope, discard it and fallback to listenAddrs is available') + // Try Legacy + addresses = message.listenAddrs } - // Update peers data in PeerStore try { - // TODO: Store as certified record - - this.peerStore.addressBook.set(id, peerRecord.multiaddrs.map((addr) => multiaddr(addr))) + this.peerStore.addressBook.set(id, addresses.map((addr) => multiaddr(addr))) } catch (err) { - return log.error('received invalid listen addrs', err) + log.error('received invalid addrs', err) } // Update the protocols @@ -359,20 +319,25 @@ class IdentifyService { * @return {Buffer} */ async _getSelfPeerRecord () { - // TODO: Verify if updated + // TODO: support invalidation when dynamic multiaddrs are supported 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) + try { + const peerRecord = new PeerRecord({ + peerId: this.peerId, + multiaddrs: this._libp2p.multiaddrs + }) + const envelope = await Envelope.seal(peerRecord, this.peerId) - this._selfRecord = envelope.marshal() + this._selfRecord = envelope.marshal() - return this._selfRecord + return this._selfRecord + } catch (err) { + log.error('failed to get self peer record') + } + return null } } @@ -383,8 +348,6 @@ module.exports.IdentifyService = IdentifyService */ module.exports.multicodecs = { IDENTIFY: MULTICODEC_IDENTIFY, - 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 + IDENTIFY_PUSH: MULTICODEC_IDENTIFY_PUSH } module.exports.Message = Message diff --git a/test/identify/index.spec.js b/test/identify/index.spec.js index 68bfd6772b..b92dc83a6e 100644 --- a/test/identify/index.spec.js +++ b/test/identify/index.spec.js @@ -18,6 +18,7 @@ const { codes: Errors } = require('../../src/errors') const { IdentifyService, multicodecs } = require('../../src/identify') const Peers = require('../fixtures/peers') const Libp2p = require('../../src') +const Envelope = require('../../src/record/envelope') const baseOptions = require('../utils/base-options.browser') const pkg = require('../../package.json') @@ -25,19 +26,13 @@ const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser') const remoteAddr = MULTIADDRS_WEBSOCKETS[0] const listenMaddrs = [multiaddr('/ip4/127.0.0.1/tcp/15002/ws')] -const protocols = new Map([ - [multicodecs.IDENTIFY, () => { }], - [multicodecs.IDENTIFY_PUSH, () => { }] -]) - -const protocolsLegacy = new Map([ - [multicodecs.IDENTIFY_1_0_0, () => { }], - [multicodecs.IDENTIFY_PUSH_1_0_0, () => { }] -]) - describe('Identify', () => { let localPeer let remotePeer + const protocols = new Map([ + [multicodecs.IDENTIFY, () => {}], + [multicodecs.IDENTIFY_PUSH, () => {}] + ]) before(async () => { [localPeer, remotePeer] = (await Promise.all([ @@ -50,7 +45,7 @@ describe('Identify', () => { sinon.restore() }) - it('should be able to identify another peer with 1.0.0 legacy protocol', async () => { + it('should be able to identify another peer', async () => { const localIdentify = new IdentifyService({ libp2p: { peerId: localPeer, @@ -65,7 +60,7 @@ describe('Identify', () => { }, multiaddrs: listenMaddrs }, - protocols: protocolsLegacy + protocols }) const remoteIdentify = new IdentifyService({ @@ -74,15 +69,15 @@ describe('Identify', () => { connectionManager: new EventEmitter(), multiaddrs: listenMaddrs }, - protocols: protocolsLegacy + protocols }) const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234') - const localConnectionMock = { newStream: () => { }, remotePeer } + const localConnectionMock = { newStream: () => {}, remotePeer } const remoteConnectionMock = { remoteAddr: observedAddr } const [local, remote] = duplexPair() - sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY_1_0_0 }) + sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY }) sinon.spy(localIdentify.peerStore.addressBook, 'set') sinon.spy(localIdentify.peerStore.protoBook, 'set') @@ -93,7 +88,7 @@ describe('Identify', () => { remoteIdentify.handleMessage({ connection: remoteConnectionMock, stream: remote, - protocol: multicodecs.IDENTIFY_1_0_0 + protocol: multicodecs.IDENTIFY }) ]) @@ -108,14 +103,15 @@ describe('Identify', () => { expect(call.args[1][0].equals(listenMaddrs[0])) }) - it('should be able to identify another peer', async () => { + // LEGACY + it('should be able to identify another peer with no certified peer records support', async () => { const localIdentify = new IdentifyService({ libp2p: { peerId: localPeer, connectionManager: new EventEmitter(), peerStore: { addressBook: { - set: () => { } + set: () => {} }, protoBook: { set: () => { } @@ -144,6 +140,7 @@ describe('Identify', () => { const [local, remote] = duplexPair() sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY }) + sinon.stub(Envelope, 'openAndCertify').throws() sinon.spy(localIdentify.peerStore.addressBook, 'set') sinon.spy(localIdentify.peerStore.protoBook, 'set') @@ -224,9 +221,9 @@ describe('Identify', () => { }) describe('push', () => { - it('should be able to push identify updates to another peer with 1.0.0 legacy protocols', async () => { + it('should be able to push identify updates to another peer', async () => { const connectionManager = new EventEmitter() - connectionManager.getConnection = () => {} + connectionManager.getConnection = () => { } const localIdentify = new IdentifyService({ libp2p: { @@ -235,8 +232,8 @@ describe('Identify', () => { multiaddrs: listenMaddrs }, protocols: new Map([ - [multicodecs.IDENTIFY_1_0_0], - [multicodecs.IDENTIFY_PUSH_1_0_0], + [multicodecs.IDENTIFY], + [multicodecs.IDENTIFY_PUSH], ['/echo/1.0.0'] ]) }) @@ -257,12 +254,12 @@ describe('Identify', () => { }) // Setup peer protocols and multiaddrs - const localProtocols = new Set([multicodecs.IDENTIFY_1_0_0, multicodecs.IDENTIFY_PUSH_1_0_0, '/echo/1.0.0']) - const localConnectionMock = { newStream: () => {} } + const localProtocols = new Set([multicodecs.IDENTIFY, multicodecs.IDENTIFY_PUSH, '/echo/1.0.0']) + const localConnectionMock = { newStream: () => { } } const remoteConnectionMock = { remotePeer: localPeer } const [local, remote] = duplexPair() - sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY_PUSH_1_0_0 }) + sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY_PUSH }) sinon.spy(remoteIdentify.peerStore.addressBook, 'set') sinon.spy(remoteIdentify.peerStore.protoBook, 'set') @@ -273,7 +270,7 @@ describe('Identify', () => { remoteIdentify.handleMessage({ connection: remoteConnectionMock, stream: remote, - protocol: multicodecs.IDENTIFY_PUSH_1_0_0 + protocol: multicodecs.IDENTIFY_PUSH }) ]) @@ -287,7 +284,8 @@ describe('Identify', () => { expect(protocols).to.eql(Array.from(localProtocols)) }) - it('should be able to push identify updates to another peer', async () => { + // LEGACY + it('should be able to push identify updates to another peer with no certified peer records support', async () => { const connectionManager = new EventEmitter() connectionManager.getConnection = () => { } @@ -321,11 +319,12 @@ describe('Identify', () => { // Setup peer protocols and multiaddrs const localProtocols = new Set([multicodecs.IDENTIFY, multicodecs.IDENTIFY_PUSH, '/echo/1.0.0']) - const localConnectionMock = { newStream: () => { } } + const localConnectionMock = { newStream: () => {} } const remoteConnectionMock = { remotePeer: localPeer } const [local, remote] = duplexPair() sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY_PUSH }) + sinon.stub(Envelope, 'openAndCertify').throws() sinon.spy(remoteIdentify.peerStore.addressBook, 'set') sinon.spy(remoteIdentify.peerStore.protoBook, 'set')