Skip to content

Commit 97e347e

Browse files
lidelhacdias
authored andcommitted
fix(routing/http): support legacy peerids
we already return base58, but we did not support them as input. libp2p specs state implementations MUST support both, it is also better for end users if we are liberal in inputs and support both notations: https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation
1 parent 8924807 commit 97e347e

File tree

3 files changed

+87
-14
lines changed

3 files changed

+87
-14
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ The following emojis are used to highlight certain changes:
2222

2323
### Fixed
2424

25+
- 🛠️`routing/http/server`: delegated peer routing endpoint now supports both [PeerID string notaitons from libp2p specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation).
26+
2527
### Security
2628

2729
## [v0.18.0]

routing/http/server/server.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,16 +242,21 @@ func (s *server) findProvidersNDJSON(w http.ResponseWriter, provIter iter.Result
242242
func (s *server) findPeers(w http.ResponseWriter, r *http.Request) {
243243
pidStr := mux.Vars(r)["peer-id"]
244244

245-
// pidStr must be in CIDv1 format. Therefore, use [cid.Decode]. We can't use
246-
// [peer.Decode] because that would allow other formats to pass through.
245+
// While specification states that peer-id is expected to be in CIDv1 format, reality
246+
// is the clients will often learn legacy PeerID string from other sources,
247+
// and try to use it.
248+
// See https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation
249+
// We are liberal in inputs here, and uplift legacy PeerID to CID if necessary.
250+
// Rationale: it is better to fix this common mistake than to error and break peer routing.
247251
cid, err := cid.Decode(pidStr)
248252
if err != nil {
249-
if pid, err := peer.Decode(pidStr); err == nil {
250-
writeErr(w, "FindPeers", http.StatusBadRequest, fmt.Errorf("the value is a peer ID, try using its CID representation: %s", peer.ToCid(pid).String()))
253+
// check if input is peer ID in legacy format
254+
if pid, err2 := peer.Decode(pidStr); err2 == nil {
255+
cid = peer.ToCid(pid)
251256
} else {
252-
writeErr(w, "FindPeers", http.StatusBadRequest, fmt.Errorf("unable to parse peer ID: %w", err))
257+
writeErr(w, "FindPeers", http.StatusBadRequest, fmt.Errorf("unable to parse peer ID as libp2p-key CID: %w", err))
258+
return
253259
}
254-
return
255260
}
256261

257262
pid, err := peer.FromCid(cid)

routing/http/server/server_test.go

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,24 +147,87 @@ func TestPeers(t *testing.T) {
147147
return resp
148148
}
149149

150-
t.Run("GET /routing/v1/peers/{non-peer-cid} returns 400", func(t *testing.T) {
150+
t.Run("GET /routing/v1/peers/{non-peer-valid-cid} returns 400", func(t *testing.T) {
151151
t.Parallel()
152152

153153
router := &mockContentRouter{}
154154
resp := makeRequest(t, router, mediaTypeJSON, "bafkqaaa")
155155
require.Equal(t, 400, resp.StatusCode)
156156
})
157157

158-
t.Run("GET /routing/v1/peers/{base58-peer-id} returns 400", func(t *testing.T) {
158+
t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body (JSON)", func(t *testing.T) {
159159
t.Parallel()
160160

161161
_, pid := makePeerID(t)
162+
results := iter.FromSlice([]iter.Result[*types.PeerRecord]{
163+
{Val: &types.PeerRecord{
164+
Schema: types.SchemaPeer,
165+
ID: &pid,
166+
Protocols: []string{"transport-bitswap", "transport-foo"},
167+
Addrs: []types.Multiaddr{},
168+
}},
169+
{Val: &types.PeerRecord{
170+
Schema: types.SchemaPeer,
171+
ID: &pid,
172+
Protocols: []string{"transport-foo"},
173+
Addrs: []types.Multiaddr{},
174+
}},
175+
})
176+
162177
router := &mockContentRouter{}
163-
resp := makeRequest(t, router, mediaTypeJSON, b58.Encode([]byte(pid)))
164-
require.Equal(t, 400, resp.StatusCode)
178+
router.On("FindPeers", mock.Anything, pid, 20).Return(results, nil)
179+
180+
libp2pKeyCID := peer.ToCid(pid).String()
181+
resp := makeRequest(t, router, mediaTypeJSON, libp2pKeyCID)
182+
require.Equal(t, 200, resp.StatusCode)
183+
184+
header := resp.Header.Get("Content-Type")
185+
require.Equal(t, mediaTypeJSON, header)
186+
187+
body, err := io.ReadAll(resp.Body)
188+
require.NoError(t, err)
189+
190+
expectedBody := `{"Peers":[{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-bitswap","transport-foo"],"Schema":"peer"},{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-foo"],"Schema":"peer"}]}`
191+
require.Equal(t, expectedBody, string(body))
192+
})
193+
194+
t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body (NDJSON)", func(t *testing.T) {
195+
t.Parallel()
196+
197+
_, pid := makePeerID(t)
198+
results := iter.FromSlice([]iter.Result[*types.PeerRecord]{
199+
{Val: &types.PeerRecord{
200+
Schema: types.SchemaPeer,
201+
ID: &pid,
202+
Protocols: []string{"transport-bitswap", "transport-foo"},
203+
Addrs: []types.Multiaddr{},
204+
}},
205+
{Val: &types.PeerRecord{
206+
Schema: types.SchemaPeer,
207+
ID: &pid,
208+
Protocols: []string{"transport-foo"},
209+
Addrs: []types.Multiaddr{},
210+
}},
211+
})
212+
213+
router := &mockContentRouter{}
214+
router.On("FindPeers", mock.Anything, pid, 0).Return(results, nil)
215+
216+
libp2pKeyCID := peer.ToCid(pid).String()
217+
resp := makeRequest(t, router, mediaTypeNDJSON, libp2pKeyCID)
218+
require.Equal(t, 200, resp.StatusCode)
219+
220+
header := resp.Header.Get("Content-Type")
221+
require.Equal(t, mediaTypeNDJSON, header)
222+
223+
body, err := io.ReadAll(resp.Body)
224+
require.NoError(t, err)
225+
226+
expectedBody := `{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-bitswap","transport-foo"],"Schema":"peer"}` + "\n" + `{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-foo"],"Schema":"peer"}` + "\n"
227+
require.Equal(t, expectedBody, string(body))
165228
})
166229

167-
t.Run("GET /routing/v1/peers/{cid-peer-id} returns 200 with correct body (JSON)", func(t *testing.T) {
230+
t.Run("GET /routing/v1/peers/{legacy-base58-peer-id} returns 200 with correct body (JSON)", func(t *testing.T) {
168231
t.Parallel()
169232

170233
_, pid := makePeerID(t)
@@ -186,7 +249,8 @@ func TestPeers(t *testing.T) {
186249
router := &mockContentRouter{}
187250
router.On("FindPeers", mock.Anything, pid, 20).Return(results, nil)
188251

189-
resp := makeRequest(t, router, mediaTypeJSON, peer.ToCid(pid).String())
252+
legacyPeerID := b58.Encode([]byte(pid))
253+
resp := makeRequest(t, router, mediaTypeJSON, legacyPeerID)
190254
require.Equal(t, 200, resp.StatusCode)
191255

192256
header := resp.Header.Get("Content-Type")
@@ -199,7 +263,7 @@ func TestPeers(t *testing.T) {
199263
require.Equal(t, expectedBody, string(body))
200264
})
201265

202-
t.Run("GET /routing/v1/peers/{cid-peer-id} returns 200 with correct body (NDJSON)", func(t *testing.T) {
266+
t.Run("GET /routing/v1/peers/{legacy-base58-peer-id} returns 200 with correct body (NDJSON)", func(t *testing.T) {
203267
t.Parallel()
204268

205269
_, pid := makePeerID(t)
@@ -221,7 +285,8 @@ func TestPeers(t *testing.T) {
221285
router := &mockContentRouter{}
222286
router.On("FindPeers", mock.Anything, pid, 0).Return(results, nil)
223287

224-
resp := makeRequest(t, router, mediaTypeNDJSON, peer.ToCid(pid).String())
288+
legacyPeerID := b58.Encode([]byte(pid))
289+
resp := makeRequest(t, router, mediaTypeNDJSON, legacyPeerID)
225290
require.Equal(t, 200, resp.StatusCode)
226291

227292
header := resp.Header.Get("Content-Type")
@@ -233,6 +298,7 @@ func TestPeers(t *testing.T) {
233298
expectedBody := `{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-bitswap","transport-foo"],"Schema":"peer"}` + "\n" + `{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-foo"],"Schema":"peer"}` + "\n"
234299
require.Equal(t, expectedBody, string(body))
235300
})
301+
236302
}
237303

238304
func makeName(t *testing.T) (crypto.PrivKey, ipns.Name) {

0 commit comments

Comments
 (0)