diff --git a/gateway/core/corehttp/hostname.go b/gateway/core/corehttp/hostname.go index b6246e281..c02c3aeec 100644 --- a/gateway/core/corehttp/hostname.go +++ b/gateway/core/corehttp/hostname.go @@ -349,15 +349,27 @@ func knownSubdomainDetails(hostname string, knownGateways gatewayHosts) (gw *con return nil, "", "", "", false } +// isDomainNameAndNotPeerID returns bool if string looks like a valid DNS name AND is not a PeerID +func isDomainNameAndNotPeerID(hostname string) bool { + if len(hostname) == 0 { + return false + } + if _, err := peer.Decode(hostname); err == nil { + return false + } + _, ok := dns.IsDomainName(hostname) + return ok +} + // isDNSLinkName returns bool if a valid DNS TXT record exist for provided host func isDNSLinkName(ctx context.Context, ipfs iface.CoreAPI, host string) bool { - fqdn := stripPort(host) + dnslinkName := stripPort(host) - if _, ok := dns.IsDomainName(fqdn); !ok && len(fqdn) == 0 { + if !isDomainNameAndNotPeerID(dnslinkName) { return false } - name := "/ipns/" + fqdn + name := "/ipns/" + dnslinkName // check if DNSLink exists depth := options.Name.ResolveOption(nsopts.Depth(1)) _, err := ipfs.Name().Resolve(ctx, name, depth) @@ -476,7 +488,7 @@ func toSubdomainURL(hostname, path string, r *http.Request, ipfs iface.CoreAPI) } // Normalize problematic PeerIDs (eg. ed25519+identity) to CID representation - if _, ok := dns.IsDomainName(rootID); !ok && isPeerIDNamespace(ns) { + if isPeerIDNamespace(ns) && !isDomainNameAndNotPeerID(rootID) { peerID, err := peer.Decode(rootID) // Note: PeerID CIDv1 with protobuf multicodec will fail, but we fix it // in the next block diff --git a/gateway/core/corehttp/hostname_test.go b/gateway/core/corehttp/hostname_test.go index 9bee6768a..6575ee1e8 100644 --- a/gateway/core/corehttp/hostname_test.go +++ b/gateway/core/corehttp/hostname_test.go @@ -55,7 +55,7 @@ func TestToSubdomainURL(t *testing.T) { {httpRequest, "localhost", "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", "http://k2k4r8n0flx3ra0y5dr8fmyvwbzy3eiztmtq6th694k5a3rznayp3e4o.ipns.localhost/", nil}, {httpRequest, "localhost", "/ipns/bafybeickencdqw37dpz3ha36ewrh4undfjt2do52chtcky4rxkj447qhdm", "http://k2k4r8l9ja7hkzynavdqup76ou46tnvuaqegbd04a4o1mpbsey0meucb.ipns.localhost/", nil}, // PeerID: ed25519+identity multihash → CIDv1Base36 - {httpRequest, "localhost", "/ipns/12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5", "http://12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5.ipns.localhost/", nil}, + {httpRequest, "localhost", "/ipns/12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5", "http://k51qzi5uqu5di608geewp3nqkg0bpujoasmka7ftkyxgcm3fh1aroup0gsdrna.ipns.localhost/", nil}, {httpRequest, "sub.localhost", "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.sub.localhost/", nil}, // HTTPS requires DNSLink name to fit in a single DNS label – see "Option C" from https://github.com/ipfs/in-web-browsers/issues/169 {httpRequest, "dweb.link", "/ipns/dnslink.long-name.example.com", "http://dnslink.long-name.example.com.ipns.dweb.link/", nil}, @@ -144,6 +144,25 @@ func TestHasPrefix(t *testing.T) { } } +func TestIsDomainNameAndNotPeerID(t *testing.T) { + for _, test := range []struct { + hostname string + out bool + }{ + {"", false}, + {"example.com", true}, + {"non-icann.something", true}, + {"..", false}, + {"12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5", false}, // valid peerid + {"k51qzi5uqu5di608geewp3nqkg0bpujoasmka7ftkyxgcm3fh1aroup0gsdrna", false}, // valid peerid + } { + out := isDomainNameAndNotPeerID(test.hostname) + if out != test.out { + t.Errorf("(%s) returned '%t', expected '%t'", test.hostname, out, test.out) + } + } +} + func TestPortStripping(t *testing.T) { for _, test := range []struct { in string