diff --git a/tests/t0114_gateway_subdomains_test.go b/tests/t0114_gateway_subdomains_test.go index ef711d8b5..1bec50ed6 100644 --- a/tests/t0114_gateway_subdomains_test.go +++ b/tests/t0114_gateway_subdomains_test.go @@ -159,17 +159,6 @@ func TestGatewaySubdomains(t *testing.T) { ), ), }, - - // TODO: # *.ipns.localhost - // TODO: # .ipns.localhost - // TODO: # .ipns.localhost - - // ## ============================================================================ - // ## Test DNSLink inlining on HTTP gateways - // ## ============================================================================ - - // TODO - // ## ============================================================================ // ## Test subdomain-based requests with a custom hostname config // ## (origin per content root at http://*.example.com) @@ -234,41 +223,6 @@ func TestGatewaySubdomains(t *testing.T) { Header("Location").Equals("/ipfs/{{cid}}/wiki/Diego_Maradona.html", CIDWikipedia), ), }, - // # example.com/ipns/ - // TODO - - // # example.com/ipns/ - // TODO - - // # DNSLink on Public gateway with a single-level wildcard TLS cert - // # "Option C" from https://github.com/ipfs/in-web-browsers/issues/169 - // TODO - - // # Support ipns:// in https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler - // TODO - - // # *.ipns.example.com - // # ============================================================================ - - // # .ipns.example.com - - // # API on subdomain gateway example.com - // # ============================================================================ - - // # DNSLink: .ipns.example.com - // # (not really useful outside of localhost, as setting TLS for more than one - // # level of wildcard is a pain, but we support it if someone really wants it) - // # ============================================================================ - // TODO - - // # DNSLink on Public gateway with a single-level wildcard TLS cert - // # "Option C" from https://github.com/ipfs/in-web-browsers/issues/169 - - // ## Test subdomain handling of CIDs that do not fit in a single DNS Label (>63chars) - // ## https://github.com/ipfs/go-ipfs/issues/7318 - // ## ============================================================================ - // TODO - { Name: "request for a too long CID at localhost/ipfs/{CIDv1} returns human readable error", Hint: "router should not redirect to hostnames that could fail due to DNS limits", @@ -285,23 +239,9 @@ func TestGatewaySubdomains(t *testing.T) { Status(400). Body(Contains("CID incompatible with DNS label length limit of 63")), }, - - // # public subdomain gateway: *.example.com - // TODO: IPNS - - // # Disable selected Paths for the subdomain gateway hostname - // # ============================================================================= - - // # disable /ipns for the hostname by not whitelisting it - - // # refuse requests to Paths that were not explicitly whitelisted for the hostname - - // MANY TODOs here - // ## ============================================================================ // ## Test support for X-Forwarded-Host // ## ============================================================================ - { Name: "request for http://fake.domain.com/ipfs/{CID} doesn't match the example.com gateway", Request: Request().DoNotFollowRedirects().URL("{{scheme}}://{{domain}}/ipfs/{{cid}}", u.Scheme, "fake.domain.com", CIDv1), @@ -334,3 +274,392 @@ func TestGatewaySubdomains(t *testing.T) { RunIfSpecsAreEnabled(t, helpers.UnwrapSubdomainTests(t, tests), specs.SubdomainGateway) } + +func TestGatewaySubdomainAndIPNS(t *testing.T) { + tests := SugarTests{} + + // We're going to run the same test against multiple gateways (localhost, and a subdomain gateway) + gatewayURLs := []string{ + SubdomainGatewayURL, + SubdomainLocalhostGatewayURL, + } + + for _, gatewayURL := range gatewayURLs { + _, err := url.Parse(gatewayURL) + if err != nil { + t.Fatal(err) + } + + tests = append(tests, SugarTests{ + // # /ipns/ + + // test_localhost_gateway_response_should_contain \ + // "request for localhost/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ + // "http://localhost:$GWAY_PORT/ipns/$RSA_IPNS_IDv0" \ + // "Location: http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" + + // test_localhost_gateway_response_should_contain \ + // "request for localhost/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ + // "http://localhost:$GWAY_PORT/ipns/$ED25519_IPNS_IDv0" \ + // "Location: http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" + + // # *.ipns.localhost + + // # .ipns.localhost + + // test_localhost_gateway_response_should_contain \ + // "request for {CIDv1-libp2p-key}.ipns.localhost returns expected payload" \ + // "http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT" \ + // "$CID_VAL" + + // test_localhost_gateway_response_should_contain \ + // "request for {CIDv1-libp2p-key}.ipns.localhost returns expected payload" \ + // "http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT" \ + // "$CID_VAL" + + // test_localhost_gateway_response_should_contain \ + // "localhost request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ + // "http://${RSA_IPNS_IDv1_DAGPB}.ipns.localhost:$GWAY_PORT" \ + // "Location: http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" + + // test_localhost_gateway_response_should_contain \ + // "localhost request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ + // "http://${ED25519_IPNS_IDv1_DAGPB}.ipns.localhost:$GWAY_PORT" \ + // "Location: http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" + + // # example.com/ipns/ + + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$RSA_IPNS_IDv0" \ + // "Location: http://${RSA_IPNS_IDv1}.ipns.example.com/" + + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$ED25519_IPNS_IDv0" \ + // "Location: http://${ED25519_IPNS_IDv1}.ipns.example.com/" + + // # *.ipns.example.com + // # ============================================================================ + + // # .ipns.example.com + + // test_hostname_gateway_response_should_contain \ + // "request for {CIDv1-libp2p-key}.ipns.example.com returns expected payload" \ + // "${RSA_IPNS_IDv1}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "$CID_VAL" + + // test_hostname_gateway_response_should_contain \ + // "request for {CIDv1-libp2p-key}.ipns.example.com returns expected payload" \ + // "${ED25519_IPNS_IDv1}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "$CID_VAL" + + // test_hostname_gateway_response_should_contain \ + // "hostname request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ + // "${RSA_IPNS_IDv1_DAGPB}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "Location: http://${RSA_IPNS_IDv1}.ipns.example.com/" + + // test_hostname_gateway_response_should_contain \ + // "hostname request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ + // "${ED25519_IPNS_IDv1_DAGPB}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "Location: http://${ED25519_IPNS_IDv1}.ipns.example.com/" + + // ## Test subdomain handling of CIDs that do not fit in a single DNS Label (>63chars) + // ## https://github.com/ipfs/go-ipfs/issues/7318 + // ## ============================================================================ + + // # local: *.localhost + // test_localhost_gateway_response_should_contain \ + // "request for a ED25519 libp2p-key at localhost/ipns/{b58mh} returns Location HTTP header for DNS-safe subdomain redirect in browsers" \ + // "http://localhost:$GWAY_PORT/ipns/$IPNS_ED25519_B58MH" \ + // "Location: http://${IPNS_ED25519_B36CID}.ipns.localhost:$GWAY_PORT/" + + // # public subdomain gateway: *.example.com + + // test_hostname_gateway_response_should_contain \ + // "request for a ED25519 libp2p-key at example.com/ipns/{b58mh} returns Location HTTP header for DNS-safe subdomain redirect in browsers" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$IPNS_ED25519_B58MH" \ + // "Location: http://${IPNS_ED25519_B36CID}.ipns.example.com" + + // # disable /ipns for the hostname by not whitelisting it + // ipfs config --json Gateway.PublicGateways '{ + // "example.com": { + // "UseSubdomains": true, + // "Paths": ["/ipfs"] + // } + // }' || exit 1 + // # restart daemon to apply config changes + // test_kill_ipfs_daemon + // test_launch_ipfs_daemon_without_network + + // # refuse requests to Paths that were not explicitly whitelisted for the hostname + // test_hostname_gateway_response_should_contain \ + // "request for *.ipns.example.com returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ + // "${RSA_IPNS_IDv1}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "404 Not Found" + + // test_hostname_gateway_response_should_contain \ + // "request for *.ipns.example.com returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ + // "${ED25519_IPNS_IDv1}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "404 Not Found" + + // # refuse requests to Paths that were not explicitly whitelisted for the hostname + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/ returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$RSA_IPNS_IDv1" \ + // "404 Not Found" + + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/ returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$ED25519_IPNS_IDv1" \ + // "404 Not Found" + }...) + } + + RunIfSpecsAreEnabled(t, helpers.UnwrapSubdomainTests(t, tests), specs.SubdomainGateway, specs.IPNSResolver) +} + +func TestGatewaySubdomainAndDnsLink(t *testing.T) { + tests := SugarTests{} + + // We're going to run the same test against multiple gateways (localhost, and a subdomain gateway) + gatewayURLs := []string{ + SubdomainGatewayURL, + SubdomainLocalhostGatewayURL, + } + + for _, gatewayURL := range gatewayURLs { + _, err := url.Parse(gatewayURL) + if err != nil { + t.Fatal(err) + } + + tests = append(tests, SugarTests{ + // # /ipns/ + + // test_localhost_gateway_response_should_contain \ + // "request for localhost/ipns/{fqdn} redirects to DNSLink in subdomain" \ + // "http://localhost:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \ + // "Location: http://en.wikipedia-on-ipfs.org.ipns.localhost:$GWAY_PORT/wiki" + + // # .ipns.localhost + + // # DNSLink test requires a daemon in online mode with precached /ipns/ mapping + // test_kill_ipfs_daemon + // DNSLINK_FQDN="dnslink-test.example.com" + // export IPFS_NS_MAP="$DNSLINK_FQDN:/ipfs/$CIDv1" + // test_launch_ipfs_daemon + + // test_localhost_gateway_response_should_contain \ + // "request for {dnslink}.ipns.localhost returns expected payload" \ + // "http://$DNSLINK_FQDN.ipns.localhost:$GWAY_PORT" \ + // "$CID_VAL" + + // ## ============================================================================ + // ## Test DNSLink inlining on HTTP gateways + // ## ============================================================================ + + // # set explicit subdomain gateway config for the hostname + // ipfs config --json Gateway.PublicGateways '{ + // "localhost": { + // "UseSubdomains": true, + // "InlineDNSLink": true, + // "Paths": ["/ipfs", "/ipns", "/api"] + // }, + // "example.com": { + // "UseSubdomains": true, + // "InlineDNSLink": true, + // "Paths": ["/ipfs", "/ipns", "/api"] + // } + // }' || exit 1 + // # restart daemon to apply config changes + // test_kill_ipfs_daemon + // test_launch_ipfs_daemon_without_network + + // test_localhost_gateway_response_should_contain \ + // "request for localhost/ipns/{fqdn} redirects to DNSLink in subdomain with DNS inlining" \ + // "http://localhost:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \ + // "Location: http://en-wikipedia--on--ipfs-org.ipns.localhost:$GWAY_PORT/wiki" + + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/{fqdn} redirects to DNSLink in subdomain with DNS inlining" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \ + // "Location: http://en-wikipedia--on--ipfs-org.ipns.example.com/wiki" + + // # example.com/ipns/ + + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/{fqdn} redirects to DNSLink in subdomain" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \ + // "Location: http://en.wikipedia-on-ipfs.org.ipns.example.com/wiki" + + // # DNSLink on Public gateway with a single-level wildcard TLS cert + // # "Option C" from https://github.com/ipfs/in-web-browsers/issues/169 + // test_expect_success \ + // "request for example.com/ipns/{fqdn} with X-Forwarded-Proto redirects to TLS-safe label in subdomain" " + // curl -H \"Host: example.com\" -H \"X-Forwarded-Proto: https\" -sD - \"http://127.0.0.1:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki\" > response && + // test_should_contain \"Location: https://en-wikipedia--on--ipfs-org.ipns.example.com/wiki\" response + // " + + // # Support ipns:// in https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/?uri=ipns%3A%2F%2F.. produces redirect to /ipns/.. content path" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/?uri=ipns%3A%2F%2Fen.wikipedia-on-ipfs.org" \ + // "Location: /ipns/en.wikipedia-on-ipfs.org" + + // # DNSLink: .ipns.example.com + // # (not really useful outside of localhost, as setting TLS for more than one + // # level of wildcard is a pain, but we support it if someone really wants it) + // # ============================================================================ + + // # DNSLink test requires a daemon in online mode with precached /ipns/ mapping + // test_kill_ipfs_daemon + // DNSLINK_FQDN="dnslink-subdomain-gw-test.example.org" + // export IPFS_NS_MAP="$DNSLINK_FQDN:/ipfs/$CIDv1" + // test_launch_ipfs_daemon + + // test_hostname_gateway_response_should_contain \ + // "request for {dnslink}.ipns.example.com returns expected payload" \ + // "$DNSLINK_FQDN.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "$CID_VAL" + + // # DNSLink on Public gateway with a single-level wildcard TLS cert + // # "Option C" from https://github.com/ipfs/in-web-browsers/issues/169 + // test_expect_success \ + // "request for {single-label-dnslink}.ipns.example.com with X-Forwarded-Proto returns expected payload" " + // curl -H \"Host: dnslink--subdomain--gw--test-example-org.ipns.example.com\" -H \"X-Forwarded-Proto: https\" -sD - \"http://127.0.0.1:$GWAY_PORT\" > response && + // test_should_contain \"$CID_VAL\" response + // " + + // ## ============================================================================ + // ## Test DNSLink requests with a custom PublicGateway (hostname config) + // ## (DNSLink site at http://dnslink-test.example.com) + // ## ============================================================================ + // # disable wildcard DNSLink gateway + // # and enable it on specific NSLink hostname + // ipfs config --json Gateway.NoDNSLink true && \ + // ipfs config --json Gateway.PublicGateways '{ + // "dnslink-enabled-on-fqdn.example.org": { + // "NoDNSLink": false, + // "UseSubdomains": false, + // "Paths": ["/ipfs"] + // }, + // "only-dnslink-enabled-on-fqdn.example.org": { + // "NoDNSLink": false, + // "UseSubdomains": false, + // "Paths": [] + // }, + // "dnslink-disabled-on-fqdn.example.com": { + // "NoDNSLink": true, + // "UseSubdomains": false, + // "Paths": [] + // } + // }' || exit 1 + + // # DNSLink test requires a daemon in online mode with precached /ipns/ mapping + // DNSLINK_FQDN="dnslink-enabled-on-fqdn.example.org" + // ONLY_DNSLINK_FQDN="only-dnslink-enabled-on-fqdn.example.org" + // NO_DNSLINK_FQDN="dnslink-disabled-on-fqdn.example.com" + // export IPFS_NS_MAP="$DNSLINK_FQDN:/ipfs/$CIDv1,$ONLY_DNSLINK_FQDN:/ipfs/$DIR_CID" + + // # DNSLink enabled + + // test_hostname_gateway_response_should_contain \ + // "request for http://{dnslink-fqdn}/ PublicGateway returns expected payload" \ + // "$DNSLINK_FQDN" \ + // "http://127.0.0.1:$GWAY_PORT/" \ + // "$CID_VAL" + + // test_hostname_gateway_response_should_contain \ + // "request for {dnslink-fqdn}/ipfs/{cid} returns expected payload when /ipfs is on Paths whitelist" \ + // "$DNSLINK_FQDN" \ + // "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ + // "$CID_VAL" + + // # Test for a fun edge case: DNSLink-only gateway without /ipfs/ namespace + // # mounted, and with subdirectory named "ipfs" ¯\_(ツ)_/¯ + // test_hostname_gateway_response_should_contain \ + // "request for {dnslink-fqdn}/ipfs/file.txt returns data from content root when /ipfs in not on Paths whitelist" \ + // "$ONLY_DNSLINK_FQDN" \ + // "http://127.0.0.1:$GWAY_PORT/ipfs/file.txt" \ + // "I am a txt file" + + // test_hostname_gateway_response_should_contain \ + // "request for {dnslink-fqdn}/ipns/{peerid} returns 404 when path is not whitelisted" \ + // "$DNSLINK_FQDN" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$RSA_IPNS_IDv0" \ + // "404 Not Found" + + // test_hostname_gateway_response_should_contain \ + // "request for {dnslink-fqdn}/ipns/{peerid} returns 404 when path is not whitelisted" \ + // "$DNSLINK_FQDN" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$ED25519_IPNS_IDv0" \ + // "404 Not Found" + + // # DNSLink disabled + + // test_hostname_gateway_response_should_contain \ + // "request for http://{dnslink-fqdn}/ returns 404 when NoDNSLink=true" \ + // "$NO_DNSLINK_FQDN" \ + // "http://127.0.0.1:$GWAY_PORT/" \ + // "404 Not Found" + + // test_hostname_gateway_response_should_contain \ + // "request for {dnslink-fqdn}/ipfs/{cid} returns 404 when path is not whitelisted" \ + // "$NO_DNSLINK_FQDN" \ + // "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv0" \ + // "404 Not Found" + + // ## ============================================================================ + // ## Test wildcard DNSLink (any hostname, with default config) + // ## ============================================================================ + + // test_kill_ipfs_daemon + + // # enable wildcard DNSLink gateway (any value in Host header) + // # and remove custom PublicGateways + // ipfs config --json Gateway.NoDNSLink false && \ + // ipfs config --json Gateway.PublicGateways '{}' || exit 1 + + // # DNSLink test requires a daemon in online mode with precached /ipns/ mapping + // DNSLINK_FQDN="wildcard-dnslink-not-in-config.example.com" + // export IPFS_NS_MAP="$DNSLINK_FQDN:/ipfs/$CIDv1" + + // # restart daemon to apply config changes + // test_launch_ipfs_daemon + + // # make sure test setup is valid (fail if CoreAPI is unable to resolve) + // test_expect_success "spoofed DNSLink record resolves in cli" " + // ipfs resolve /ipns/$DNSLINK_FQDN > result && + // test_should_contain \"$CIDv1\" result && + // ipfs cat /ipns/$DNSLINK_FQDN > result && + // test_should_contain \"$CID_VAL\" result + // " + + // # gateway test + // + // test_hostname_gateway_response_should_contain \ + // "request for http://{dnslink-fqdn}/ (wildcard) returns expected payload" \ + // "$DNSLINK_FQDN" \ + // "http://127.0.0.1:$GWAY_PORT/" \ + // "$CID_VAL" + }...) + } + + RunIfSpecsAreEnabled(t, helpers.UnwrapSubdomainTests(t, tests), specs.SubdomainGateway, specs.DNSLinkResolver) +}