Skip to content
This repository was archived by the owner on Mar 10, 2020. It is now read-only.

Commit 6e6d7a2

Browse files
olizillaAlan Shaw
authored and
Alan Shaw
committed
fix: handle peer-info validation errors (#887)
BREAKING CHANGE. Previously swarm.peers would throw an uncaught error if any peer in the reponse could have its peerId or multiaddr validated. This PR catches errors that occur while validating the peer info. The returned array will contain an entry for every peer in the ipfs response. peer-info objects that couldn't be validated, now have an `error` property and a `rawPeerInfo` property. This at least means the count of peers in the response will be accurate, and there the info is available to the caller. This means that callers now have to deal with peer-info objects that may not have a `peer or `addr` property. Adds `nock` tests to exercice the code under different error conditions. Doing so uncovered a bug in our legacy go-ipfs <= 0.4.4 peer info parsing, which is also fixed. The code was trying to decapusalate the peerId from the multiaddr, but doing so trims the peerId rather than returning it. fixes #885 License: MIT Signed-off-by: Oli Evans <[email protected]>
1 parent da35b0f commit 6e6d7a2

File tree

4 files changed

+165
-43
lines changed

4 files changed

+165
-43
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"libp2p-crypto": "~0.14.0",
4949
"lodash": "^4.17.11",
5050
"lru-cache": "^4.1.3",
51-
"multiaddr": "^5.0.0",
51+
"multiaddr": "^5.0.2",
5252
"multibase": "~0.5.0",
5353
"multihashes": "~0.4.14",
5454
"ndjson": "^1.5.0",
@@ -87,6 +87,7 @@
8787
"gulp": "^3.9.1",
8888
"interface-ipfs-core": "~0.86.0",
8989
"ipfsd-ctl": "~0.40.0",
90+
"nock": "^10.0.2",
9091
"pull-stream": "^3.6.9",
9192
"stream-equal": "^1.1.1"
9293
},

src/swarm/peers.js

+51-42
Original file line numberDiff line numberDiff line change
@@ -10,56 +10,65 @@ module.exports = (send) => {
1010
callback = opts
1111
opts = {}
1212
}
13-
1413
const verbose = opts.v || opts.verbose
15-
1614
send({
1715
path: 'swarm/peers',
1816
qs: opts
19-
}, (err, result) => {
17+
}, (err, response) => {
2018
if (err) {
2119
return callback(err)
2220
}
21+
const peerInfo = parsePeersResponse(verbose, response)
22+
callback(null, peerInfo)
23+
})
24+
})
25+
}
2326

24-
// go-ipfs <= 0.4.4
25-
if (result.Strings) {
26-
return callback(null, result.Strings.map((p) => {
27-
const res = {}
28-
29-
if (verbose) {
30-
const parts = p.split(' ')
31-
res.addr = multiaddr(parts[0])
32-
res.latency = parts[1]
33-
} else {
34-
res.addr = multiaddr(p)
35-
}
36-
37-
res.peer = PeerId.createFromB58String(
38-
res.addr.decapsulate('ipfs')
39-
)
40-
41-
return res
42-
}))
43-
}
44-
45-
// go-ipfs >= 0.4.5
46-
callback(null, (result.Peers || []).map((p) => {
47-
const res = {
48-
addr: multiaddr(p.Addr),
49-
peer: PeerId.createFromB58String(p.Peer),
50-
muxer: p.Muxer
51-
}
52-
53-
if (p.Latency) {
54-
res.latency = p.Latency
55-
}
27+
function parsePeersResponse (verbose, response) {
28+
// go-ipfs <= 0.4.4
29+
if (Array.isArray(response.Strings)) {
30+
return response.Strings.map(parseLegacyPeer.bind(null, verbose))
31+
}
32+
// go-ipfs >= 0.4.5
33+
if (Array.isArray(response.Peers)) {
34+
return response.Peers.map(parsePeer.bind(null, verbose))
35+
}
36+
return []
37+
}
5638

57-
if (p.Streams) {
58-
res.streams = p.Streams
59-
}
39+
function parseLegacyPeer (verbose, peer) {
40+
const res = {}
41+
try {
42+
if (verbose) {
43+
const parts = peer.split(' ')
44+
res.addr = multiaddr(parts[0])
45+
res.latency = parts[1]
46+
} else {
47+
res.addr = multiaddr(peer)
48+
}
49+
res.peer = PeerId.createFromB58String(res.addr.getPeerId())
50+
} catch (error) {
51+
res.error = error
52+
res.rawPeerInfo = peer
53+
}
54+
return res
55+
}
6056

61-
return res
62-
}))
63-
})
64-
})
57+
function parsePeer (verbose, peer) {
58+
const res = {}
59+
try {
60+
res.addr = multiaddr(peer.Addr)
61+
res.peer = PeerId.createFromB58String(peer.Peer)
62+
res.muxer = peer.Muxer
63+
} catch (error) {
64+
res.error = error
65+
res.rawPeerInfo = peer
66+
}
67+
if (peer.Latency) {
68+
res.latency = peer.Latency
69+
}
70+
if (peer.Streams) {
71+
res.streams = peer.Streams
72+
}
73+
return res
6574
}

test/node.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
'use strict'
2+
require('./node/swarm')

test/node/swarm.js

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const nock = require('nock')
5+
const chai = require('chai')
6+
const dirtyChai = require('dirty-chai')
7+
const expect = chai.expect
8+
chai.use(dirtyChai)
9+
10+
const IPFSApi = require('../../src')
11+
12+
describe('.swarm.peers', function () {
13+
this.timeout(50 * 1000) // slow CI
14+
15+
const ipfs = IPFSApi('/ip4/127.0.0.1/tcp/5001')
16+
const apiUrl = 'http://127.0.0.1:5001'
17+
18+
it('handles a peer response', (done) => {
19+
const response = { Peers: [{ Addr: '/ip4/104.131.131.82/tcp/4001', Peer: 'QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ', Latency: '', Muxer: '', Streams: null }] }
20+
21+
const scope = nock(apiUrl)
22+
.post('/api/v0/swarm/peers')
23+
.query(true)
24+
.reply(200, response)
25+
26+
ipfs.swarm.peers((err, res) => {
27+
expect(err).to.not.exist()
28+
expect(res).to.be.a('array')
29+
expect(res.length).to.equal(1)
30+
expect(res[0].error).to.not.exist()
31+
expect(res[0].addr.toString()).to.equal(response.Peers[0].Addr)
32+
expect(res[0].peer.toB58String()).to.equal(response.Peers[0].Peer)
33+
expect(scope.isDone()).to.equal(true)
34+
done()
35+
})
36+
})
37+
38+
it('handles a go-ipfs <= 0.4.4 peer response', (done) => {
39+
const response = { Strings: ['/ip4/73.109.217.59/tcp/49311/ipfs/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm'] }
40+
41+
const scope = nock(apiUrl)
42+
.post('/api/v0/swarm/peers')
43+
.query(true)
44+
.reply(200, response)
45+
46+
ipfs.swarm.peers((err, res) => {
47+
expect(err).to.not.exist()
48+
expect(res).to.be.a('array')
49+
expect(res.length).to.equal(1)
50+
expect(res[0].error).to.not.exist()
51+
expect(res[0].addr.toString()).to.equal('/ip4/73.109.217.59/tcp/49311/ipfs/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm')
52+
expect(res[0].peer.toB58String()).to.equal('QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm')
53+
expect(scope.isDone()).to.equal(true)
54+
done()
55+
})
56+
})
57+
58+
it('handles an ip6 quic peer', (done) => {
59+
const response = { Peers: [{ Addr: '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/udp/4001/quic', Peer: 'QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC', Latency: '', Muxer: '', Streams: null }] }
60+
61+
const scope = nock(apiUrl)
62+
.post('/api/v0/swarm/peers')
63+
.query(true)
64+
.reply(200, response)
65+
66+
ipfs.swarm.peers((err, res) => {
67+
expect(err).to.not.exist()
68+
expect(res).to.be.a('array')
69+
expect(res.length).to.equal(1)
70+
expect(res[0].error).to.not.exist()
71+
expect(res[0].addr.toString()).to.equal(response.Peers[0].Addr)
72+
expect(res[0].peer.toB58String()).to.equal(response.Peers[0].Peer)
73+
expect(scope.isDone()).to.equal(true)
74+
done()
75+
})
76+
})
77+
78+
it('handles unvalidatable peer addr', (done) => {
79+
const response = { Peers: [{ Addr: '/ip4/104.131.131.82/future-tech', Peer: 'QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC', Latency: '', Muxer: '', Streams: null }] }
80+
81+
const scope = nock(apiUrl)
82+
.post('/api/v0/swarm/peers')
83+
.query(true)
84+
.reply(200, response)
85+
86+
ipfs.swarm.peers((err, res) => {
87+
expect(err).to.not.exist()
88+
expect(res).to.be.a('array')
89+
expect(res.length).to.equal(1)
90+
expect(res[0].error).to.exist()
91+
expect(res[0].rawPeerInfo).to.deep.equal(response.Peers[0])
92+
expect(scope.isDone()).to.equal(true)
93+
done()
94+
})
95+
})
96+
97+
it('handles an error response', (done) => {
98+
const scope = nock(apiUrl)
99+
.post('/api/v0/swarm/peers')
100+
.query(true)
101+
.replyWithError('something awful happened')
102+
103+
ipfs.swarm.peers((err, res) => {
104+
expect(err.message).to.equal('something awful happened')
105+
expect(res).to.not.exist()
106+
expect(scope.isDone()).to.equal(true)
107+
done()
108+
})
109+
})
110+
})

0 commit comments

Comments
 (0)