diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index d2bb9f78a8e..1512c3ed225 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -448,7 +448,7 @@ func serveHTTPGateway(req cmds.Request) (error, <-chan error) { corehttp.CommandsROOption(*req.InvocContext()), corehttp.VersionOption(), corehttp.IPNSHostnameOption(), - corehttp.GatewayOption(writable), + corehttp.GatewayOption(writable, cfg.Gateway.PathPrefixes), } if len(cfg.Gateway.RootRedirect) > 0 { diff --git a/cmd/ipfswatch/main.go b/cmd/ipfswatch/main.go index aa6210adce9..bf173bbbaa1 100644 --- a/cmd/ipfswatch/main.go +++ b/cmd/ipfswatch/main.go @@ -84,7 +84,7 @@ func run(ipfsPath, watchPath string) error { if *http { addr := "/ip4/127.0.0.1/tcp/5001" var opts = []corehttp.ServeOption{ - corehttp.GatewayOption(true), + corehttp.GatewayOption(true, nil), corehttp.WebUIOption, corehttp.CommandsOption(cmdCtx(node, ipfsPath)), } diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go index ce6ed50dac6..c2831dfe1ee 100644 --- a/core/corehttp/gateway.go +++ b/core/corehttp/gateway.go @@ -17,9 +17,10 @@ type Gateway struct { } type GatewayConfig struct { - Headers map[string][]string - BlockList *BlockList - Writable bool + Headers map[string][]string + BlockList *BlockList + Writable bool + PathPrefixes []string } func NewGateway(conf GatewayConfig) *Gateway { @@ -48,10 +49,11 @@ func (g *Gateway) ServeOption() ServeOption { } } -func GatewayOption(writable bool) ServeOption { +func GatewayOption(writable bool, prefixes []string) ServeOption { g := NewGateway(GatewayConfig{ - Writable: writable, - BlockList: &BlockList{}, + Writable: writable, + BlockList: &BlockList{}, + PathPrefixes: prefixes, }) return g.ServeOption() } diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index 54ef9c7b7f6..d8bd7676f89 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -131,8 +131,13 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request // It will be prepended to links in directory listings and the index.html redirect. prefix := "" if prefixHdr := r.Header["X-Ipfs-Gateway-Prefix"]; len(prefixHdr) > 0 { - log.Debugf("X-Ipfs-Gateway-Prefix: %s", prefixHdr[0]) - prefix = prefixHdr[0] + prfx := prefixHdr[0] + for _, p := range i.config.PathPrefixes { + if prfx == p || strings.HasPrefix(prfx, p+"/") { + prefix = prfx + break + } + } } // IPNSHostnameOption might have constructed an IPNS path using the Host header. diff --git a/core/corehttp/gateway_test.go b/core/corehttp/gateway_test.go index d52d8f5513f..acff7826207 100644 --- a/core/corehttp/gateway_test.go +++ b/core/corehttp/gateway_test.go @@ -98,7 +98,7 @@ func newTestServerAndNode(t *testing.T, ns mockNamesys) (*httptest.Server, *core ts.Listener, VersionOption(), IPNSHostnameOption(), - GatewayOption(false), + GatewayOption(false, []string{"/good-prefix"}), ) if err != nil { t.Fatal(err) @@ -227,7 +227,7 @@ func TestIPNSHostnameRedirect(t *testing.T) { t.Fatal(err) } req.Host = "example.net" - req.Header.Set("X-Ipfs-Gateway-Prefix", "/prefix") + req.Header.Set("X-Ipfs-Gateway-Prefix", "/good-prefix") res, err = doWithoutRedirect(req) if err != nil { @@ -241,8 +241,8 @@ func TestIPNSHostnameRedirect(t *testing.T) { hdr = res.Header["Location"] if len(hdr) < 1 { t.Errorf("location header not present") - } else if hdr[0] != "/prefix/foo/" { - t.Errorf("location header is %v, expected /prefix/foo/", hdr[0]) + } else if hdr[0] != "/good-prefix/foo/" { + t.Errorf("location header is %v, expected /good-prefix/foo/", hdr[0]) } } @@ -387,7 +387,7 @@ func TestIPNSHostnameBacklinks(t *testing.T) { t.Fatal(err) } req.Host = "example.net" - req.Header.Set("X-Ipfs-Gateway-Prefix", "/prefix") + req.Header.Set("X-Ipfs-Gateway-Prefix", "/good-prefix") res, err = doWithoutRedirect(req) if err != nil { @@ -402,13 +402,57 @@ func TestIPNSHostnameBacklinks(t *testing.T) { s = string(body) t.Logf("body: %s\n", string(body)) - if !strings.Contains(s, "Index of /prefix") { + if !strings.Contains(s, "Index of /good-prefix") { t.Fatalf("expected a path in directory listing") } - if !strings.Contains(s, "") { + if !strings.Contains(s, "") { t.Fatalf("expected backlink in directory listing") } - if !strings.Contains(s, "") { + if !strings.Contains(s, "") { + t.Fatalf("expected file in directory listing") + } + + // make request to directory listing with illegal prefix + req, err = http.NewRequest("GET", ts.URL, nil) + if err != nil { + t.Fatal(err) + } + req.Host = "example.net" + req.Header.Set("X-Ipfs-Gateway-Prefix", "/bad-prefix") + + res, err = doWithoutRedirect(req) + if err != nil { + t.Fatal(err) + } + + // make request to directory listing with evil prefix + req, err = http.NewRequest("GET", ts.URL, nil) + if err != nil { + t.Fatal(err) + } + req.Host = "example.net" + req.Header.Set("X-Ipfs-Gateway-Prefix", "//good-prefix/foo") + + res, err = doWithoutRedirect(req) + if err != nil { + t.Fatal(err) + } + + // expect correct backlinks without illegal prefix + body, err = ioutil.ReadAll(res.Body) + if err != nil { + t.Fatalf("error reading response: %s", err) + } + s = string(body) + t.Logf("body: %s\n", string(body)) + + if !strings.Contains(s, "Index of /") { + t.Fatalf("expected a path in directory listing") + } + if !strings.Contains(s, "") { + t.Fatalf("expected backlink in directory listing") + } + if !strings.Contains(s, "") { t.Fatalf("expected file in directory listing") } } diff --git a/repo/config/gateway.go b/repo/config/gateway.go index 07bc9aad2cb..a8ba7059071 100644 --- a/repo/config/gateway.go +++ b/repo/config/gateway.go @@ -5,4 +5,5 @@ type Gateway struct { HTTPHeaders map[string][]string // HTTP headers to return with the gateway RootRedirect string Writable bool + PathPrefixes []string } diff --git a/repo/config/init.go b/repo/config/init.go index 1cbc9f4956a..3dbc1b3f522 100644 --- a/repo/config/init.go +++ b/repo/config/init.go @@ -65,6 +65,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: Gateway{ RootRedirect: "", Writable: false, + PathPrefixes: []string{}, }, } diff --git a/test/supernode_client/main.go b/test/supernode_client/main.go index 5e1a25a8bd1..348f3c45b2e 100644 --- a/test/supernode_client/main.go +++ b/test/supernode_client/main.go @@ -109,7 +109,7 @@ func run() error { opts := []corehttp.ServeOption{ corehttp.CommandsOption(cmdCtx(node, repoPath)), - corehttp.GatewayOption(false), + corehttp.GatewayOption(false, nil), } if *cat {