Skip to content

Commit 4dd1d74

Browse files
committed
feat(gw): configurable trusted mode
1 parent 53821c2 commit 4dd1d74

File tree

8 files changed

+92
-22
lines changed

8 files changed

+92
-22
lines changed

config/gateway.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package config
22

3-
const DefaultInlineDNSLink = false
3+
const (
4+
DefaultInlineDNSLink = false
5+
DefaultTrustedMode = true
6+
)
47

58
type GatewaySpec struct {
69
// Paths is explicit list of path prefixes that should be handled by
@@ -25,6 +28,11 @@ type GatewaySpec struct {
2528
// (FQDN) into a single DNS label in order to interop with wildcard TLS certs
2629
// and Origin per CID isolation provided by rules like https://publicsuffix.org
2730
InlineDNSLink Flag
31+
32+
// TrustedMode configures this gateway to respond to trusted requests.
33+
// Disabling this option enables a Trustless only gateway, as per:
34+
// https://specs.ipfs.tech/http-gateways/trustless-gateway/.
35+
TrustedMode Flag
2836
}
2937

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

67+
// TrustedMode configures this gateway to respond to trusted requests.
68+
// Disabling this option enables a Trustless only gateway, as per:
69+
// https://specs.ipfs.tech/http-gateways/trustless-gateway/. This can
70+
// be overridden per FQDN in PublicGateways.
71+
TrustedMode Flag
72+
5973
// PublicGateways configures behavior of known public gateways.
6074
// Each key is a fully qualified domain name (FQDN).
6175
PublicGateways map[string]*GatewaySpec

core/corehttp/gateway.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,11 @@ import (
2828

2929
func GatewayOption(paths ...string) ServeOption {
3030
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
31-
cfg, err := n.Repo.Config()
31+
gwConfig, err := getGatewayConfig(n)
3232
if err != nil {
3333
return nil, err
3434
}
3535

36-
headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders))
37-
for h, v := range cfg.Gateway.HTTPHeaders {
38-
headers[http.CanonicalHeaderKey(h)] = v
39-
}
40-
41-
gateway.AddAccessControlHeaders(headers)
42-
43-
gwConfig := gateway.Config{
44-
Headers: headers,
45-
}
46-
4736
gwAPI, err := newGatewayBackend(n)
4837
if err != nil {
4938
return nil, err
@@ -65,7 +54,7 @@ func GatewayOption(paths ...string) ServeOption {
6554

6655
func HostnameOption() ServeOption {
6756
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
68-
cfg, err := n.Repo.Config()
57+
gwConfig, err := getGatewayConfig(n)
6958
if err != nil {
7059
return nil, err
7160
}
@@ -75,9 +64,8 @@ func HostnameOption() ServeOption {
7564
return nil, err
7665
}
7766

78-
publicGateways := convertPublicGateways(cfg.Gateway.PublicGateways)
7967
childMux := http.NewServeMux()
80-
mux.HandleFunc("/", gateway.WithHostname(childMux, gwAPI, publicGateways, cfg.Gateway.NoDNSLink).ServeHTTP)
68+
mux.HandleFunc("/", gateway.WithHostname(gwConfig, gwAPI, childMux).ServeHTTP)
8169
return childMux, nil
8270
}
8371
}
@@ -212,6 +200,28 @@ var defaultKnownGateways = map[string]*gateway.Specification{
212200
"localhost": subdomainGatewaySpec,
213201
}
214202

203+
func getGatewayConfig(n *core.IpfsNode) (gateway.Config, error) {
204+
cfg, err := n.Repo.Config()
205+
if err != nil {
206+
return gateway.Config{}, err
207+
}
208+
209+
headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders))
210+
for h, v := range cfg.Gateway.HTTPHeaders {
211+
headers[http.CanonicalHeaderKey(h)] = v
212+
}
213+
gateway.AddAccessControlHeaders(headers)
214+
215+
gwConfig := gateway.Config{
216+
Headers: headers,
217+
TrustedMode: cfg.Gateway.TrustedMode.WithDefault(config.DefaultTrustedMode),
218+
NoDNSLink: cfg.Gateway.NoDNSLink,
219+
PublicGateways: convertPublicGateways(cfg.Gateway.PublicGateways),
220+
}
221+
222+
return gwConfig, nil
223+
}
224+
215225
func convertPublicGateways(publicGateways map[string]*config.GatewaySpec) map[string]*gateway.Specification {
216226
gws := map[string]*gateway.Specification{}
217227

@@ -234,6 +244,7 @@ func convertPublicGateways(publicGateways map[string]*config.GatewaySpec) map[st
234244
NoDNSLink: gw.NoDNSLink,
235245
UseSubdomains: gw.UseSubdomains,
236246
InlineDNSLink: gw.InlineDNSLink.WithDefault(config.DefaultInlineDNSLink),
247+
TrustedMode: gw.TrustedMode.WithDefault(config.DefaultTrustedMode),
237248
}
238249
}
239250

docs/config.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ config file at runtime.
5050
- [`Gateway`](#gateway)
5151
- [`Gateway.NoFetch`](#gatewaynofetch)
5252
- [`Gateway.NoDNSLink`](#gatewaynodnslink)
53+
- [`Gateway.TrustedMode`](#gatewaytrustedmode)
5354
- [`Gateway.HTTPHeaders`](#gatewayhttpheaders)
5455
- [`Gateway.RootRedirect`](#gatewayrootredirect)
5556
- [`Gateway.FastDirIndexThreshold`](#gatewayfastdirindexthreshold)
@@ -60,6 +61,7 @@ config file at runtime.
6061
- [`Gateway.PublicGateways: UseSubdomains`](#gatewaypublicgateways-usesubdomains)
6162
- [`Gateway.PublicGateways: NoDNSLink`](#gatewaypublicgateways-nodnslink)
6263
- [`Gateway.PublicGateways: InlineDNSLink`](#gatewaypublicgateways-inlinednslink)
64+
- [`Gateway.PublicGateways: TrustedMode`](#gatewaypublicgateways-trustedmode)
6365
- [Implicit defaults of `Gateway.PublicGateways`](#implicit-defaults-of-gatewaypublicgateways)
6466
- [`Gateway` recipes](#gateway-recipes)
6567
- [`Identity`](#identity)
@@ -646,6 +648,16 @@ Default: `false`
646648

647649
Type: `bool`
648650

651+
#### `Gateway.TrustedMode`
652+
653+
An optional flag to explicitly configure whether this gateway responds to trusted
654+
requests, or not. By default, it is enabled. When disabling this option, the gateway
655+
operates in Trustless mode only: https://specs.ipfs.tech/http-gateways/trustless-gateway/.
656+
657+
Default: `true`
658+
659+
Type: `flag`
660+
649661
### `Gateway.HTTPHeaders`
650662

651663
Headers to set on gateway responses.
@@ -790,6 +802,16 @@ Default: `false`
790802
791803
Type: `flag`
792804
805+
#### `Gateway.PublicGateways: TrustedMode`
806+
807+
An optional flag to explicitly configure whether this gateway responds to trusted
808+
requests, or not. By default, it is enabled. When disabling this option, the gateway
809+
operates in Trustless mode only: https://specs.ipfs.tech/http-gateways/trustless-gateway/.
810+
811+
Default: `true`
812+
813+
Type: `flag`
814+
793815
#### Implicit defaults of `Gateway.PublicGateways`
794816
795817
Default entries for `localhost` hostname and loopback IPs are always present.

docs/examples/kubo-as-a-library/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ go 1.18
77
replace github.com/ipfs/kubo => ./../../..
88

99
require (
10-
github.com/ipfs/boxo v0.8.1
10+
github.com/ipfs/boxo v0.8.2-0.20230502122446-5e3ab69daa0e
1111
github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
1212
github.com/libp2p/go-libp2p v0.27.1
1313
github.com/multiformats/go-multiaddr v0.9.0

docs/examples/kubo-as-a-library/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
321321
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
322322
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
323323
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
324-
github.com/ipfs/boxo v0.8.1 h1:3DkKBCK+3rdEB5t77WDShUXXhktYwH99mkAsgajsKrU=
325-
github.com/ipfs/boxo v0.8.1/go.mod h1:xJ2hVb4La5WyD7GvKYE0lq2g1rmQZoCD2K4WNrV6aZI=
324+
github.com/ipfs/boxo v0.8.2-0.20230502122446-5e3ab69daa0e h1:0bBRxguln+XK35KyzWqyMf4bZGz/dcPa3R010Ts6Wvc=
325+
github.com/ipfs/boxo v0.8.2-0.20230502122446-5e3ab69daa0e/go.mod h1:bORAHrH6hUtDZjbzTEaLrSpTdyhHKDIpjDRT+A14B7w=
326326
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
327327
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
328328
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ require (
1616
github.com/gogo/protobuf v1.3.2
1717
github.com/google/uuid v1.3.0
1818
github.com/hashicorp/go-multierror v1.1.1
19-
github.com/ipfs/boxo v0.8.1
19+
github.com/ipfs/boxo v0.8.2-0.20230502122446-5e3ab69daa0e
2020
github.com/ipfs/go-block-format v0.1.2
2121
github.com/ipfs/go-cid v0.4.1
2222
github.com/ipfs/go-cidutil v0.1.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
356356
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
357357
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
358358
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
359-
github.com/ipfs/boxo v0.8.1 h1:3DkKBCK+3rdEB5t77WDShUXXhktYwH99mkAsgajsKrU=
360-
github.com/ipfs/boxo v0.8.1/go.mod h1:xJ2hVb4La5WyD7GvKYE0lq2g1rmQZoCD2K4WNrV6aZI=
359+
github.com/ipfs/boxo v0.8.2-0.20230502122446-5e3ab69daa0e h1:0bBRxguln+XK35KyzWqyMf4bZGz/dcPa3R010Ts6Wvc=
360+
github.com/ipfs/boxo v0.8.2-0.20230502122446-5e3ab69daa0e/go.mod h1:bORAHrH6hUtDZjbzTEaLrSpTdyhHKDIpjDRT+A14B7w=
361361
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
362362
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
363363
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=

test/cli/gateway_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,4 +506,27 @@ func TestGateway(t *testing.T) {
506506
})
507507
})
508508
})
509+
510+
t.Run("TrustedMode Disabled", func(t *testing.T) {
511+
// Trusted and trustless responses are tested in more detail in Boxo.
512+
t.Parallel()
513+
node := harness.NewT(t).NewNode().Init()
514+
node.UpdateConfig(func(cfg *config.Config) {
515+
cfg.Gateway.TrustedMode = config.False
516+
})
517+
node.StartDaemon()
518+
519+
cidFoo := node.IPFSAddStr("foo")
520+
521+
t.Run("trusted response fails", func(t *testing.T) {
522+
t.Parallel()
523+
assert.Equal(t, http.StatusNotImplemented, node.GatewayClient().Get("/ipfs/"+cidFoo).StatusCode)
524+
})
525+
526+
t.Run("trustless response succeeds", func(t *testing.T) {
527+
t.Parallel()
528+
assert.Equal(t, http.StatusOK, node.GatewayClient().Get("/ipfs/"+cidFoo+"?format=raw").StatusCode)
529+
})
530+
})
531+
509532
}

0 commit comments

Comments
 (0)