Skip to content

Commit d8d1f54

Browse files
committed
feat(gateway): redirect ipns b58mh peer id to cid
1 parent 2835752 commit d8d1f54

3 files changed

Lines changed: 58 additions & 1 deletion

File tree

.github/workflows/gateway-sharness.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
with:
2929
repository: ipfs/kubo
3030
path: kubo
31-
ref: 503edee648e29c62888f05fa146ab13d9c65077d
31+
ref: d17449d
3232
- name: Install Missing Tools
3333
run: sudo apt install -y socat net-tools fish libxml2-utils
3434
- name: Restore Go Cache

gateway/gateway_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,3 +548,15 @@ func TestGoGetSupport(t *testing.T) {
548548
assert.Nil(t, err)
549549
assert.Equal(t, http.StatusOK, res.StatusCode)
550550
}
551+
552+
func TestIpnsBase58MultihashRedirect(t *testing.T) {
553+
ts, _, _ := newTestServerAndNode(t, nil)
554+
t.Logf("test server url: %s", ts.URL)
555+
556+
req, err := http.NewRequest(http.MethodGet, ts.URL+"/ipns/12D3KooWRBy97UB99e3J6hiPesre1MZeuNQvfan4gBziswrRJsNK?keep=query", nil)
557+
assert.Nil(t, err)
558+
559+
res, err := doWithoutRedirect(req)
560+
assert.Nil(t, err)
561+
assert.Equal(t, "/ipns/bafzaajaiaejcbzdibmxyzdjbbehgvizh6g5tikvy47mshdy6gwbruvgwvd24seje?keep=query", res.Header.Get("Location"))
562+
}

gateway/handler.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
ipath "github.com/ipfs/boxo/coreiface/path"
2020
cid "github.com/ipfs/go-cid"
2121
logging "github.com/ipfs/go-log"
22+
"github.com/libp2p/go-libp2p/core/peer"
23+
"github.com/multiformats/go-multihash"
2224
prometheus "github.com/prometheus/client_golang/prometheus"
2325
"go.opentelemetry.io/otel"
2426
"go.opentelemetry.io/otel/attribute"
@@ -325,6 +327,10 @@ func (i *handler) getOrHeadHandler(w http.ResponseWriter, r *http.Request) {
325327
return
326328
}
327329

330+
if handleIpnsB58mhToCidRedirection(w, r) {
331+
return
332+
}
333+
328334
contentPath := ipath.New(r.URL.Path)
329335
ctx := context.WithValue(r.Context(), ContentPathKey, contentPath)
330336
r = r.WithContext(ctx)
@@ -844,6 +850,45 @@ func handleServiceWorkerRegistration(r *http.Request) (err *ErrorResponse) {
844850
return nil
845851
}
846852

853+
// handleIpnsB58mhToCidRedirection redirects from /ipns/b58mh to /ipns/cid in
854+
// the most cost-effective way.
855+
func handleIpnsB58mhToCidRedirection(w http.ResponseWriter, r *http.Request) bool {
856+
if w.Header().Get("Location") != "" {
857+
// Ignore this if there is already a redirection in place. This happens
858+
// if there is a subdomain redirection. In that case, the path is already
859+
// converted to CIDv1.
860+
return false
861+
}
862+
863+
pathParts := strings.Split(r.URL.Path, "/")
864+
if len(pathParts) < 3 {
865+
return false
866+
}
867+
868+
if pathParts[1] != "ipns" {
869+
return false
870+
}
871+
872+
s := pathParts[2]
873+
874+
// Similarly to peer.Decode, check the prefix first as it is less computationally
875+
// expensive. Base58 encoded peer IDs will start with a '1'.
876+
if !strings.HasPrefix(s, "1") {
877+
return false
878+
}
879+
880+
// Decode the base58 encoded sha256 or identity multihash.
881+
m, err := multihash.FromB58String(s)
882+
if err != nil {
883+
return false
884+
}
885+
886+
pathParts[2] = peer.ToCid(peer.ID(m)).String()
887+
r.URL.Path = strings.Join(pathParts, "/")
888+
http.Redirect(w, r, r.URL.String(), http.StatusFound)
889+
return true
890+
}
891+
847892
// Attempt to fix redundant /ipfs/ namespace as long as resulting
848893
// 'intended' path is valid. This is in case gremlins were tickled
849894
// wrong way and user ended up at /ipfs/ipfs/{cid} or /ipfs/ipns/{id}

0 commit comments

Comments
 (0)