Skip to content

Commit 05642b0

Browse files
committed
refactor: cleanup isDNSLinkName mess
1 parent c091fd6 commit 05642b0

File tree

7 files changed

+176
-141
lines changed

7 files changed

+176
-141
lines changed

examples/gateway-car/api.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ func (api *blocksGateway) ResolvePath(ctx context.Context, p ifacepath.Path) (if
139139
return ifacepath.NewResolvedPath(ipath, node, root, gopath.Join(rest...)), nil
140140
}
141141

142+
func (api *blocksGateway) HasDNSLinkRecord(ctx context.Context, host string) bool {
143+
// Not implemented.
144+
return false
145+
}
146+
142147
func (api *blocksGateway) resolveNode(ctx context.Context, p ifacepath.Path) (format.Node, error) {
143148
rp, err := api.ResolvePath(ctx, p)
144149
if err != nil {

examples/go.mod

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,7 @@ require (
3535
github.com/go-logr/stdr v1.2.2 // indirect
3636
github.com/gogo/protobuf v1.3.2 // indirect
3737
github.com/golang/protobuf v1.5.2 // indirect
38-
github.com/google/gopacket v1.1.19 // indirect
3938
github.com/google/uuid v1.3.0 // indirect
40-
github.com/hashicorp/errwrap v1.1.0 // indirect
41-
github.com/hashicorp/go-multierror v1.1.1 // indirect
4239
github.com/hashicorp/golang-lru v0.5.4 // indirect
4340
github.com/ipfs/bbloom v0.0.4 // indirect
4441
github.com/ipfs/go-bitfield v1.0.0 // indirect
@@ -55,20 +52,12 @@ require (
5552
github.com/ipfs/go-log v1.0.5 // indirect
5653
github.com/ipfs/go-log/v2 v2.5.1 // indirect
5754
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
58-
github.com/ipfs/go-namesys v0.7.0 // indirect
5955
github.com/ipfs/go-verifcid v0.0.2 // indirect
6056
github.com/ipld/go-car v0.5.0 // indirect
6157
github.com/jbenet/goprocess v0.1.4 // indirect
6258
github.com/klauspost/cpuid/v2 v2.2.3 // indirect
6359
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
64-
github.com/libp2p/go-cidranger v1.1.0 // indirect
6560
github.com/libp2p/go-libp2p v0.23.4 // indirect
66-
github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
67-
github.com/libp2p/go-libp2p-kad-dht v0.19.0 // indirect
68-
github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect
69-
github.com/libp2p/go-libp2p-record v0.2.0 // indirect
70-
github.com/libp2p/go-msgio v0.2.0 // indirect
71-
github.com/libp2p/go-netroute v0.2.0 // indirect
7261
github.com/libp2p/go-openssl v0.1.0 // indirect
7362
github.com/mattn/go-isatty v0.0.17 // indirect
7463
github.com/mattn/go-pointer v0.0.1 // indirect
@@ -79,7 +68,6 @@ require (
7968
github.com/multiformats/go-base32 v0.1.0 // indirect
8069
github.com/multiformats/go-base36 v0.2.0 // indirect
8170
github.com/multiformats/go-multiaddr v0.8.0 // indirect
82-
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
8371
github.com/multiformats/go-multibase v0.1.1 // indirect
8472
github.com/multiformats/go-multicodec v0.7.0 // indirect
8573
github.com/multiformats/go-multihash v0.2.1 // indirect
@@ -96,11 +84,8 @@ require (
9684
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
9785
github.com/spaolacci/murmur3 v1.1.0 // indirect
9886
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect
99-
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
10087
github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect
10188
github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa // indirect
102-
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
103-
go.opencensus.io v0.23.0 // indirect
10489
go.opentelemetry.io/otel v1.12.0 // indirect
10590
go.opentelemetry.io/otel/trace v1.12.0 // indirect
10691
go.uber.org/atomic v1.10.0 // indirect

examples/go.sum

Lines changed: 0 additions & 43 deletions
Large diffs are not rendered by default.

gateway/gateway.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ type API interface {
3939
// exist due to a missing link, it should return an error of type:
4040
// https://pkg.go.dev/github.com/ipfs/[email protected]/resolver#ErrNoLink
4141
ResolvePath(context.Context, path.Path) (path.Resolved, error)
42+
43+
// HasDNSLinkRecord returns if the provided path has a DNSLink TXT record.
44+
// It does not perform any validation, only checks for the existence of
45+
// a DNSLink TXT record.
46+
HasDNSLinkRecord(context.Context, string) bool
4247
}
4348

4449
// A helper function to clean up a set of headers:

gateway/gateway_test.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package gateway
2+
3+
import (
4+
"context"
5+
"errors"
6+
"strings"
7+
8+
cid "github.com/ipfs/go-cid"
9+
"github.com/ipfs/go-datastore"
10+
syncds "github.com/ipfs/go-datastore/sync"
11+
"github.com/ipfs/go-libipfs/blocks"
12+
"github.com/ipfs/go-libipfs/files"
13+
"github.com/ipfs/go-namesys"
14+
path "github.com/ipfs/go-path"
15+
iface "github.com/ipfs/interface-go-ipfs-core"
16+
nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
17+
ipath "github.com/ipfs/interface-go-ipfs-core/path"
18+
"github.com/libp2p/go-libp2p/core/crypto"
19+
)
20+
21+
type mockNamesys map[string]path.Path
22+
23+
func (m mockNamesys) Resolve(ctx context.Context, name string, opts ...nsopts.ResolveOpt) (value path.Path, err error) {
24+
cfg := nsopts.DefaultResolveOpts()
25+
for _, o := range opts {
26+
o(&cfg)
27+
}
28+
depth := cfg.Depth
29+
if depth == nsopts.UnlimitedDepth {
30+
// max uint
31+
depth = ^uint(0)
32+
}
33+
for strings.HasPrefix(name, "/ipns/") {
34+
if depth == 0 {
35+
return value, namesys.ErrResolveRecursion
36+
}
37+
depth--
38+
39+
var ok bool
40+
value, ok = m[name]
41+
if !ok {
42+
return "", namesys.ErrResolveFailed
43+
}
44+
name = value.String()
45+
}
46+
return value, nil
47+
}
48+
49+
func (m mockNamesys) ResolveAsync(ctx context.Context, name string, opts ...nsopts.ResolveOpt) <-chan namesys.Result {
50+
out := make(chan namesys.Result, 1)
51+
v, err := m.Resolve(ctx, name, opts...)
52+
out <- namesys.Result{Path: v, Err: err}
53+
close(out)
54+
return out
55+
}
56+
57+
func (m mockNamesys) Publish(ctx context.Context, name crypto.PrivKey, value path.Path, opts ...nsopts.PublishOption) error {
58+
return errors.New("not implemented for mockNamesys")
59+
}
60+
61+
func (m mockNamesys) GetResolver(subs string) (namesys.Resolver, bool) {
62+
return nil, false
63+
}
64+
65+
type mockApi struct {
66+
ns mockNamesys
67+
}
68+
69+
func newMockApi() *mockApi {
70+
71+
syncds.MutexWrap(datastore.NewMapDatastore())
72+
73+
return &mockApi{
74+
ns: mockNamesys{},
75+
}
76+
}
77+
78+
func (m *mockApi) GetUnixFsNode(context.Context, ipath.Resolved) (files.Node, error) {
79+
return nil, errors.New("not implemented")
80+
}
81+
82+
func (m *mockApi) LsUnixFsDir(context.Context, ipath.Resolved) (<-chan iface.DirEntry, error) {
83+
return nil, errors.New("not implemented")
84+
}
85+
86+
func (m *mockApi) GetBlock(context.Context, cid.Cid) (blocks.Block, error) {
87+
return nil, errors.New("not implemented")
88+
}
89+
90+
func (m *mockApi) GetIPNSRecord(context.Context, cid.Cid) ([]byte, error) {
91+
return nil, errors.New("not implemented")
92+
}
93+
94+
func (m *mockApi) IsCached(context.Context, ipath.Path) bool {
95+
return false
96+
}
97+
98+
func (m *mockApi) ResolvePath(context.Context, ipath.Path) (ipath.Resolved, error) {
99+
return nil, errors.New("not implemented")
100+
}
101+
102+
func (m *mockApi) HasDNSLinkRecord(ctx context.Context, hostname string) bool {
103+
_, err := m.ns.Resolve(ctx, "/ipns/"+hostname, nsopts.Depth(1))
104+
return err == nil || err == namesys.ErrResolveRecursion
105+
}

gateway/hostname.go

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import (
1010
"strings"
1111

1212
cid "github.com/ipfs/go-cid"
13-
"github.com/ipfs/go-namesys"
14-
"github.com/ipfs/interface-go-ipfs-core/path"
1513
"github.com/libp2p/go-libp2p/core/peer"
1614
dns "github.com/miekg/dns"
1715

@@ -113,7 +111,7 @@ func WithHostname(next http.Handler, api API, publicGateways map[string]*Specifi
113111
// Not a whitelisted path
114112

115113
// Try DNSLink, if it was not explicitly disabled for the hostname
116-
if !gw.NoDNSLink && isDNSLinkName(r.Context(), api, host) {
114+
if !gw.NoDNSLink && hasDNSLinkRecord(r.Context(), api, host) {
117115
// rewrite path and handle as DNSLink
118116
r.URL.Path = "/ipns/" + stripPort(host) + r.URL.Path
119117
next.ServeHTTP(w, withHostnameContext(r, host))
@@ -184,7 +182,6 @@ func WithHostname(next http.Handler, api API, publicGateways map[string]*Specifi
184182
}
185183
}
186184
} else { // rootID is not a CID..
187-
188185
// Check if rootID is a single DNS label with an inlined
189186
// DNSLink FQDN a single DNS label. We support this so
190187
// loading DNSLink names over TLS "just works" on public
@@ -200,10 +197,10 @@ func WithHostname(next http.Handler, api API, publicGateways map[string]*Specifi
200197
// https://my-v--long-example-com.ipns.dweb.link
201198
if ns == "ipns" && !strings.Contains(rootID, ".") {
202199
// if there is no TXT recordfor rootID
203-
if !isDNSLinkName(r.Context(), api, rootID) {
200+
if !hasDNSLinkRecord(r.Context(), api, rootID) {
204201
// my-v--long-example-com → my.v-long.example.com
205202
dnslinkFQDN := toDNSLinkFQDN(rootID)
206-
if isDNSLinkName(r.Context(), api, dnslinkFQDN) {
203+
if hasDNSLinkRecord(r.Context(), api, dnslinkFQDN) {
207204
// update path prefix to use real FQDN with DNSLink
208205
pathPrefix = "/ipns/" + dnslinkFQDN
209206
}
@@ -218,13 +215,14 @@ func WithHostname(next http.Handler, api API, publicGateways map[string]*Specifi
218215
next.ServeHTTP(w, withHostnameContext(r, gwHostname))
219216
return
220217
}
218+
221219
// We don't have a known gateway. Fallback on DNSLink lookup
222220

223221
// Wildcard HTTP Host check:
224222
// 1. is wildcard DNSLink enabled (Gateway.NoDNSLink=false)?
225223
// 2. does Host header include a fully qualified domain name (FQDN)?
226224
// 3. does DNSLink record exist in DNS?
227-
if !noDNSLink && isDNSLinkName(r.Context(), api, host) {
225+
if !noDNSLink && hasDNSLinkRecord(r.Context(), api, host) {
228226
// rewrite path and handle as DNSLink
229227
r.URL.Path = "/ipns/" + stripPort(host) + r.URL.Path
230228
ctx := context.WithValue(r.Context(), DNSLinkHostnameKey, host)
@@ -262,18 +260,15 @@ func isDomainNameAndNotPeerID(hostname string) bool {
262260
return ok
263261
}
264262

265-
// isDNSLinkName returns bool if a valid DNS TXT record exist for provided host
266-
func isDNSLinkName(ctx context.Context, api API, host string) bool {
263+
// hasDNSLinkRecord returns if a DNS TXT record exists for the provided host.
264+
func hasDNSLinkRecord(ctx context.Context, api API, host string) bool {
267265
dnslinkName := stripPort(host)
268266

269267
if !isDomainNameAndNotPeerID(dnslinkName) {
270268
return false
271269
}
272270

273-
name := "/ipns/" + dnslinkName
274-
_, err := api.ResolvePath(ctx, path.New(name))
275-
// check if DNSLink exists
276-
return err == nil || err == namesys.ErrResolveRecursion
271+
return api.HasDNSLinkRecord(ctx, dnslinkName)
277272
}
278273

279274
func isSubdomainNamespace(ns string) bool {
@@ -456,7 +451,7 @@ func toSubdomainURL(hostname, path string, r *http.Request, inlineDNSLink bool,
456451
// represented as a single DNS label:
457452
// https://my-v--long-example-com.ipns.dweb.link
458453
if (inlineDNSLink || isHTTPS) && ns == "ipns" && strings.Contains(rootID, ".") {
459-
if isDNSLinkName(r.Context(), api, rootID) {
454+
if hasDNSLinkRecord(r.Context(), api, rootID) {
460455
// my.v-long.example.com → my-v--long-example-com
461456
dnsLabel, err := toDNSLinkDNSLabel(rootID)
462457
if err != nil {

0 commit comments

Comments
 (0)