Skip to content

Commit

Permalink
feat(gw): configurable trusted mode
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed May 16, 2023
1 parent 65b8d53 commit ba6876a
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 26 deletions.
16 changes: 15 additions & 1 deletion config/gateway.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package config

const DefaultInlineDNSLink = false
const (
DefaultInlineDNSLink = false
DefaultDeserializedResponses = true
)

type GatewaySpec struct {
// Paths is explicit list of path prefixes that should be handled by
Expand All @@ -25,6 +28,11 @@ type GatewaySpec struct {
// (FQDN) into a single DNS label in order to interop with wildcard TLS certs
// and Origin per CID isolation provided by rules like https://publicsuffix.org
InlineDNSLink Flag

// DeserializedResponses configures this gateway to respond to deserialized
// responses. Disabling this option enables a Trustless Gateway, as per:
// https://specs.ipfs.tech/http-gateways/trustless-gateway/.
DeserializedResponses Flag
}

// Gateway contains options for the HTTP gateway server.
Expand Down Expand Up @@ -56,6 +64,12 @@ type Gateway struct {
// This flag can be overridden per FQDN in PublicGateways.
NoDNSLink bool

// DeserializedResponses configures this gateway to respond to deserialized
// requests. Disabling this option enables a Trustless only gateway, as per:
// https://specs.ipfs.tech/http-gateways/trustless-gateway/. This can
// be overridden per FQDN in PublicGateways.
DeserializedResponses Flag

// PublicGateways configures behavior of known public gateways.
// Each key is a fully qualified domain name (FQDN).
PublicGateways map[string]*GatewaySpec
Expand Down
49 changes: 30 additions & 19 deletions core/corehttp/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,11 @@ import (

func GatewayOption(paths ...string) ServeOption {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
cfg, err := n.Repo.Config()
gwConfig, err := getGatewayConfig(n)
if err != nil {
return nil, err
}

headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders))
for h, v := range cfg.Gateway.HTTPHeaders {
headers[http.CanonicalHeaderKey(h)] = v
}

gateway.AddAccessControlHeaders(headers)

gwConfig := gateway.Config{
Headers: headers,
}

gwAPI, err := newGatewayBackend(n)
if err != nil {
return nil, err
Expand All @@ -65,7 +54,7 @@ func GatewayOption(paths ...string) ServeOption {

func HostnameOption() ServeOption {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
cfg, err := n.Repo.Config()
gwConfig, err := getGatewayConfig(n)
if err != nil {
return nil, err
}
Expand All @@ -75,9 +64,8 @@ func HostnameOption() ServeOption {
return nil, err
}

publicGateways := convertPublicGateways(cfg.Gateway.PublicGateways)
childMux := http.NewServeMux()
mux.HandleFunc("/", gateway.WithHostname(childMux, gwAPI, publicGateways, cfg.Gateway.NoDNSLink).ServeHTTP)
mux.HandleFunc("/", gateway.WithHostname(gwConfig, gwAPI, childMux).ServeHTTP)
return childMux, nil
}
}
Expand Down Expand Up @@ -212,6 +200,28 @@ var defaultKnownGateways = map[string]*gateway.Specification{
"localhost": subdomainGatewaySpec,
}

func getGatewayConfig(n *core.IpfsNode) (gateway.Config, error) {
cfg, err := n.Repo.Config()
if err != nil {
return gateway.Config{}, err
}

headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders))
for h, v := range cfg.Gateway.HTTPHeaders {
headers[http.CanonicalHeaderKey(h)] = v
}
gateway.AddAccessControlHeaders(headers)

gwConfig := gateway.Config{
Headers: headers,
DeserializedResponses: cfg.Gateway.DeserializedResponses.WithDefault(config.DefaultDeserializedResponses),
NoDNSLink: cfg.Gateway.NoDNSLink,
PublicGateways: convertPublicGateways(cfg.Gateway.PublicGateways),
}

return gwConfig, nil
}

func convertPublicGateways(publicGateways map[string]*config.GatewaySpec) map[string]*gateway.Specification {
gws := map[string]*gateway.Specification{}

Expand All @@ -230,10 +240,11 @@ func convertPublicGateways(publicGateways map[string]*config.GatewaySpec) map[st
}

gws[hostname] = &gateway.Specification{
Paths: gw.Paths,
NoDNSLink: gw.NoDNSLink,
UseSubdomains: gw.UseSubdomains,
InlineDNSLink: gw.InlineDNSLink.WithDefault(config.DefaultInlineDNSLink),
Paths: gw.Paths,
NoDNSLink: gw.NoDNSLink,
UseSubdomains: gw.UseSubdomains,
InlineDNSLink: gw.InlineDNSLink.WithDefault(config.DefaultInlineDNSLink),
DeserializedResponses: gw.DeserializedResponses.WithDefault(config.DefaultDeserializedResponses),
}
}

Expand Down
22 changes: 22 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ config file at runtime.
- [`Gateway`](#gateway)
- [`Gateway.NoFetch`](#gatewaynofetch)
- [`Gateway.NoDNSLink`](#gatewaynodnslink)
- [`Gateway.TrustedMode`](#gatewaytrustedmode)
- [`Gateway.HTTPHeaders`](#gatewayhttpheaders)
- [`Gateway.RootRedirect`](#gatewayrootredirect)
- [`Gateway.FastDirIndexThreshold`](#gatewayfastdirindexthreshold)
Expand All @@ -60,6 +61,7 @@ config file at runtime.
- [`Gateway.PublicGateways: UseSubdomains`](#gatewaypublicgateways-usesubdomains)
- [`Gateway.PublicGateways: NoDNSLink`](#gatewaypublicgateways-nodnslink)
- [`Gateway.PublicGateways: InlineDNSLink`](#gatewaypublicgateways-inlinednslink)
- [`Gateway.PublicGateways: TrustedMode`](#gatewaypublicgateways-trustedmode)
- [Implicit defaults of `Gateway.PublicGateways`](#implicit-defaults-of-gatewaypublicgateways)
- [`Gateway` recipes](#gateway-recipes)
- [`Identity`](#identity)
Expand Down Expand Up @@ -646,6 +648,16 @@ Default: `false`

Type: `bool`

#### `Gateway.TrustedMode`

An optional flag to explicitly configure whether this gateway responds to trusted
requests, or not. By default, it is enabled. When disabling this option, the gateway
operates in Trustless mode only: https://specs.ipfs.tech/http-gateways/trustless-gateway/.

Default: `true`

Type: `flag`

### `Gateway.HTTPHeaders`

Headers to set on gateway responses.
Expand Down Expand Up @@ -790,6 +802,16 @@ Default: `false`
Type: `flag`
#### `Gateway.PublicGateways: TrustedMode`
An optional flag to explicitly configure whether this gateway responds to trusted
requests, or not. By default, it is enabled. When disabling this option, the gateway
operates in Trustless mode only: https://specs.ipfs.tech/http-gateways/trustless-gateway/.
Default: `true`
Type: `flag`
#### Implicit defaults of `Gateway.PublicGateways`
Default entries for `localhost` hostname and loopback IPs are always present.
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/kubo-as-a-library/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ go 1.18
replace github.com/ipfs/kubo => ./../../..

require (
github.com/ipfs/boxo v0.8.2-0.20230516102723-5e94b9d91816
github.com/ipfs/boxo v0.8.2-0.20230516121533-0883d3be480a
github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
github.com/libp2p/go-libp2p v0.27.3
github.com/multiformats/go-multiaddr v0.9.0
Expand Down
4 changes: 2 additions & 2 deletions docs/examples/kubo-as-a-library/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
github.com/ipfs/boxo v0.8.2-0.20230516102723-5e94b9d91816 h1:5EacqVA/Houq8q7jpecu80sWMB0Gvz0rLgRiK2Mfat0=
github.com/ipfs/boxo v0.8.2-0.20230516102723-5e94b9d91816/go.mod h1:Ej2r08Z4VIaFKqY08UXMNhwcLf6VekHhK8c+KqA1B9Y=
github.com/ipfs/boxo v0.8.2-0.20230516121533-0883d3be480a h1:ebuTuGsS8ChnqIDUm5SsgpkQXbJhb8Yjd634kD6wxb0=
github.com/ipfs/boxo v0.8.2-0.20230516121533-0883d3be480a/go.mod h1:Ej2r08Z4VIaFKqY08UXMNhwcLf6VekHhK8c+KqA1B9Y=
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/gogo/protobuf v1.3.2
github.com/google/uuid v1.3.0
github.com/hashicorp/go-multierror v1.1.1
github.com/ipfs/boxo v0.8.2-0.20230516102723-5e94b9d91816
github.com/ipfs/boxo v0.8.2-0.20230516121533-0883d3be480a
github.com/ipfs/go-block-format v0.1.2
github.com/ipfs/go-cid v0.4.1
github.com/ipfs/go-cidutil v0.1.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
github.com/ipfs/boxo v0.8.2-0.20230516102723-5e94b9d91816 h1:5EacqVA/Houq8q7jpecu80sWMB0Gvz0rLgRiK2Mfat0=
github.com/ipfs/boxo v0.8.2-0.20230516102723-5e94b9d91816/go.mod h1:Ej2r08Z4VIaFKqY08UXMNhwcLf6VekHhK8c+KqA1B9Y=
github.com/ipfs/boxo v0.8.2-0.20230516121533-0883d3be480a h1:ebuTuGsS8ChnqIDUm5SsgpkQXbJhb8Yjd634kD6wxb0=
github.com/ipfs/boxo v0.8.2-0.20230516121533-0883d3be480a/go.mod h1:Ej2r08Z4VIaFKqY08UXMNhwcLf6VekHhK8c+KqA1B9Y=
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
Expand Down
23 changes: 23 additions & 0 deletions test/cli/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,4 +513,27 @@ func TestGateway(t *testing.T) {
})
})
})

t.Run("DeserializedResponses Disabled", func(t *testing.T) {
// Trusted and trustless responses are tested in more detail in Boxo.
t.Parallel()
node := harness.NewT(t).NewNode().Init()
node.UpdateConfig(func(cfg *config.Config) {
cfg.Gateway.DeserializedResponses = config.False
})
node.StartDaemon()

cidFoo := node.IPFSAddStr("foo")

t.Run("trusted response fails", func(t *testing.T) {
t.Parallel()
assert.Equal(t, http.StatusNotImplemented, node.GatewayClient().Get("/ipfs/"+cidFoo).StatusCode)
})

t.Run("trustless response succeeds", func(t *testing.T) {
t.Parallel()
assert.Equal(t, http.StatusOK, node.GatewayClient().Get("/ipfs/"+cidFoo+"?format=raw").StatusCode)
})
})

}

0 comments on commit ba6876a

Please sign in to comment.