@cryptotaxi247 / kubo / commits / e166af975

core/corehttp: wrap gateway with headers, deprecate gateway /api/v0

Henrique Dias committed Jan 24, 2024 at 10:33 UTC e166af975613407739d2c8f65b5b1430fa90475b
14 files changed +52 -32
cmd/ipfs/kubo/daemon.go
+1
@@ -850,6 +850,7 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
850 corehttp.GatewayOption("/ipfs", "/ipns"),
851 corehttp.VersionOption(),
852 corehttp.CheckVersionOption(),
853 + // TODO[api-on-gw]: remove for 0.28.0: https://github.com/ipfs/kubo/issues/10312
854 corehttp.CommandsROOption(cmdctx),
855 }
856
core/corehttp/commands.go
+8
@@ -9,6 +9,7 @@ import (
9 "strconv"
10 "strings"
11
12 + "github.com/ipfs/boxo/gateway"
13 cmds "github.com/ipfs/go-ipfs-cmds"
14 cmdsHttp "github.com/ipfs/go-ipfs-cmds/http"
15 version "github.com/ipfs/kubo"
@@ -149,6 +150,13 @@ func commandsOption(cctx oldcmds.Context, command *cmds.Command, allowGet bool)
150 cmdHandler = withAuthSecrets(authorizations, cmdHandler)
151 }
152
153 + // TODO[api-on-gw]: remove for Kubo 0.28
154 + if command == corecommands.RootRO && allowGet {
155 + cmdHandler = gateway.NewHeaders(map[string][]string{
156 + "Link": {`<https://github.com/ipfs/kubo/issues/10312>; rel="deprecation"; type="text/html"`},
157 + }).Wrap(cmdHandler)
158 + }
159 +
160 cmdHandler = otelhttp.NewHandler(cmdHandler, "corehttp.cmdsHandler")
161 mux.Handle(APIPath+"/", cmdHandler)
162 return mux, nil
core/corehttp/gateway.go
+7 -13
@@ -28,7 +28,7 @@ import (
28
29 func GatewayOption(paths ...string) ServeOption {
30 return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
31 - config, err := getGatewayConfig(n)
31 + config, headers, err := getGatewayConfig(n)
32 if err != nil {
33 return nil, err
34 }
@@ -39,6 +39,7 @@ func GatewayOption(paths ...string) ServeOption {
39 }
40
41 handler := gateway.NewHandler(config, backend)
42 + handler = gateway.NewHeaders(headers).ApplyCors().Wrap(handler)
43 handler = otelhttp.NewHandler(handler, "Gateway")
44
45 for _, p := range paths {
@@ -51,7 +52,7 @@ func GatewayOption(paths ...string) ServeOption {
52
53 func HostnameOption() ServeOption {
54 return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
54 - config, err := getGatewayConfig(n)
55 + config, headers, err := getGatewayConfig(n)
56 if err != nil {
57 return nil, err
58 }
@@ -65,6 +66,7 @@ func HostnameOption() ServeOption {
66
67 var handler http.Handler
68 handler = gateway.NewHostnameHandler(config, backend, childMux)
69 + handler = gateway.NewHeaders(headers).ApplyCors().Wrap(handler)
70 handler = otelhttp.NewHandler(handler, "HostnameGateway")
71
72 mux.Handle("/", handler)
@@ -240,22 +242,14 @@ var defaultKnownGateways = map[string]*gateway.PublicGateway{
242 "localhost": subdomainGatewaySpec,
243 }
244
243 -func getGatewayConfig(n *core.IpfsNode) (gateway.Config, error) {
245 +func getGatewayConfig(n *core.IpfsNode) (gateway.Config, map[string][]string, error) {
246 cfg, err := n.Repo.Config()
247 if err != nil {
246 - return gateway.Config{}, err
248 + return gateway.Config{}, nil, err
249 }
250
249 - // Parse configuration headers and add the default Access Control Headers.
250 - headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders))
251 - for h, v := range cfg.Gateway.HTTPHeaders {
252 - headers[http.CanonicalHeaderKey(h)] = v
253 - }
254 - gateway.AddAccessControlHeaders(headers)
255 -
251 // Initialize gateway configuration, with empty PublicGateways, handled after.
252 gwCfg := gateway.Config{
258 - Headers: headers,
253 DeserializedResponses: cfg.Gateway.DeserializedResponses.WithDefault(config.DefaultDeserializedResponses),
254 DisableHTMLErrors: cfg.Gateway.DisableHTMLErrors.WithDefault(config.DefaultDisableHTMLErrors),
255 NoDNSLink: cfg.Gateway.NoDNSLink,
@@ -285,5 +279,5 @@ func getGatewayConfig(n *core.IpfsNode) (gateway.Config, error) {
279 }
280 }
281
288 - return gwCfg, nil
282 + return gwCfg, cfg.Gateway.HTTPHeaders, nil
283 }
core/corehttp/gateway_test.go
+1 -1
@@ -206,7 +206,7 @@ func TestDeserializedResponsesInheritance(t *testing.T) {
206 n, err := core.NewNode(context.Background(), &core.BuildCfg{Repo: r})
207 assert.NoError(t, err)
208
209 - gwCfg, err := getGatewayConfig(n)
209 + gwCfg, _, err := getGatewayConfig(n)
210 assert.NoError(t, err)
211
212 assert.Contains(t, gwCfg.PublicGateways, "example.com")
core/corehttp/routing.go
+7
@@ -6,6 +6,7 @@ import (
6 "net/http"
7 "time"
8
9 + "github.com/ipfs/boxo/gateway"
10 "github.com/ipfs/boxo/ipns"
11 "github.com/ipfs/boxo/routing/http/server"
12 "github.com/ipfs/boxo/routing/http/types"
@@ -18,7 +19,13 @@ import (
19
20 func RoutingOption() ServeOption {
21 return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
22 + _, headers, err := getGatewayConfig(n)
23 + if err != nil {
24 + return nil, err
25 + }
26 +
27 handler := server.Handler(&contentRouter{n})
28 + handler = gateway.NewHeaders(headers).ApplyCors().Wrap(handler)
29 mux.Handle("/routing/v1/", handler)
30 return mux, nil
31 }
docs/changelogs/v0.27.md
+7
@@ -6,6 +6,7 @@
6
7 - [Overview](#overview)
8 - [🔦 Highlights](#-highlights)
9 + - [Gateway: support for `/api/v0` is deprecated](#gateway-support-for-apiv0-is-deprecated)
10 - [📝 Changelog](#-changelog)
11 - [👨‍👩‍👧‍👦 Contributors](#-contributors)
12
@@ -13,6 +14,12 @@
14
15 ### 🔦 Highlights
16
17 +#### Gateway: support for `/api/v0` is deprecated
18 +
19 +Support for exposing the legacy subset of Kubo RPC via the Gateway port is deprecated and should not be used. It will be removed in the next version. You can read more in <https://github.com/ipfs/kubo/issues/10312>.
20 +
21 +If you have a legacy software that relies on this behavior, and want to expose parts of `/api/v0` next to `/ipfs`, use reverse-proxy in front of Kubo to mount both Gateway and RPC on the same port. NOTE: exposing RPC to the internet comes with security risk: make sure to specify access control via [API.Authorizations](https://github.com/ipfs/kubo/blob/master/docs/config.md#apiauthorizations).
22 +
23 ### 📝 Changelog
24
25 ### 👨‍👩‍👧‍👦 Contributors
docs/config.md
+6 -5
@@ -716,6 +716,8 @@ Toggle and configure experimental features of Kubo. Experimental features are li
716
717 Options for the HTTP gateway.
718
719 +**NOTE:** support for `/api/v0` under the gateway path is now deprecated. It will be removed in future versions: https://github.com/ipfs/kubo/issues/10312.
720 +
721 ### `Gateway.NoFetch`
722
723 When set to true, the gateway will only serve content already in the local repo
@@ -819,14 +821,14 @@ Example:
821 "Gateway": {
822 "PublicGateways": {
823 "example.com": {
822 - "Paths": ["/ipfs", "/ipns"],
824 + "Paths": ["/ipfs"],
825 }
826 }
827 }
828 }
829 ```
830
829 -Above enables `http://example.com/ipfs/*` and `http://example.com/ipns/*` but not `http://example.com/api/*`
831 +Above enables `http://example.com/ipfs/*` but not `http://example.com/ipns/*`
832
833 Default: `[]`
834
@@ -851,7 +853,6 @@ between content roots.
853 }
854 ```
855 - **Backward-compatible:** requests for content paths such as `http://{hostname}/ipfs/{cid}` produce redirect to `http://{cid}.ipfs.{hostname}`
854 - - **API:** if `/api` is on the `Paths` whitelist, `http://{hostname}/api/{cmd}` produces redirect to `http://api.{hostname}/api/{cmd}`
856
857 - `false` - enables [path gateway](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#path-gateway) at `http://{hostname}/*`
858 - Example:
@@ -860,7 +861,7 @@ between content roots.
861 "PublicGateways": {
862 "ipfs.io": {
863 "UseSubdomains": false,
863 - "Paths": ["/ipfs", "/ipns", "/api"]
864 + "Paths": ["/ipfs", "/ipns"]
865 }
866 }
867 }
@@ -969,7 +970,7 @@ Below is a list of the most common public gateway setups.
970 $ ipfs config --json Gateway.PublicGateways '{
971 "ipfs.io": {
972 "UseSubdomains": false,
972 - "Paths": ["/ipfs", "/ipns", "/api"]
973 + "Paths": ["/ipfs", "/ipns"]
974 }
975 }'
976 ```
docs/examples/kubo-as-a-library/go.mod
+1 -1
@@ -7,7 +7,7 @@ go 1.20
7 replace github.com/ipfs/kubo => ./../../..
8
9 require (
10 - github.com/ipfs/boxo v0.17.1-0.20240112124340-bcb321c857c5
10 + github.com/ipfs/boxo v0.17.1-0.20240124092521-3d57bce7998c
11 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
12 github.com/libp2p/go-libp2p v0.32.2
13 github.com/multiformats/go-multiaddr v0.12.1
docs/examples/kubo-as-a-library/go.sum
+2 -2
@@ -260,8 +260,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy
260 github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI=
261 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
262 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
263 -github.com/ipfs/boxo v0.17.1-0.20240112124340-bcb321c857c5 h1:qGPYOK8flU2YzHGq9Cb2Yeo0jjOwompAOzxOv3VSGx8=
264 -github.com/ipfs/boxo v0.17.1-0.20240112124340-bcb321c857c5/go.mod h1:pIZgTWdm3k3pLF9Uq6MB8JEcW07UDwNJjlXW1HELW80=
263 +github.com/ipfs/boxo v0.17.1-0.20240124092521-3d57bce7998c h1:A18UHDQ4V2Ai6/YsrH7kfGjA1r5SrwjQR1Lqiq68YQU=
264 +github.com/ipfs/boxo v0.17.1-0.20240124092521-3d57bce7998c/go.mod h1:pIZgTWdm3k3pLF9Uq6MB8JEcW07UDwNJjlXW1HELW80=
265 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
266 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
267 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
go.mod
+1 -1
@@ -17,7 +17,7 @@ require (
17 github.com/hashicorp/go-multierror v1.1.1
18 github.com/ipfs-shipyard/nopfs v0.0.12
19 github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c
20 - github.com/ipfs/boxo v0.17.1-0.20240112124340-bcb321c857c5
20 + github.com/ipfs/boxo v0.17.1-0.20240124092521-3d57bce7998c
21 github.com/ipfs/go-block-format v0.2.0
22 github.com/ipfs/go-cid v0.4.1
23 github.com/ipfs/go-cidutil v0.1.0
go.sum
+2 -2
@@ -325,8 +325,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy
325 github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI=
326 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
327 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
328 -github.com/ipfs/boxo v0.17.1-0.20240112124340-bcb321c857c5 h1:qGPYOK8flU2YzHGq9Cb2Yeo0jjOwompAOzxOv3VSGx8=
329 -github.com/ipfs/boxo v0.17.1-0.20240112124340-bcb321c857c5/go.mod h1:pIZgTWdm3k3pLF9Uq6MB8JEcW07UDwNJjlXW1HELW80=
328 +github.com/ipfs/boxo v0.17.1-0.20240124092521-3d57bce7998c h1:A18UHDQ4V2Ai6/YsrH7kfGjA1r5SrwjQR1Lqiq68YQU=
329 +github.com/ipfs/boxo v0.17.1-0.20240124092521-3d57bce7998c/go.mod h1:pIZgTWdm3k3pLF9Uq6MB8JEcW07UDwNJjlXW1HELW80=
330 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
331 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
332 github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=
test/dependencies/go.mod
+1 -1
@@ -103,7 +103,7 @@ require (
103 github.com/hexops/gotextdiff v1.0.3 // indirect
104 github.com/inconshreveable/mousetrap v1.1.0 // indirect
105 github.com/ipfs/bbloom v0.0.4 // indirect
106 - github.com/ipfs/boxo v0.17.1-0.20240112124340-bcb321c857c5 // indirect
106 + github.com/ipfs/boxo v0.17.1-0.20240124092521-3d57bce7998c // indirect
107 github.com/ipfs/go-block-format v0.2.0 // indirect
108 github.com/ipfs/go-cid v0.4.1 // indirect
109 github.com/ipfs/go-datastore v0.6.0 // indirect
test/dependencies/go.sum
+2 -2
@@ -342,8 +342,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
342 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
343 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
344 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
345 -github.com/ipfs/boxo v0.17.1-0.20240112124340-bcb321c857c5 h1:qGPYOK8flU2YzHGq9Cb2Yeo0jjOwompAOzxOv3VSGx8=
346 -github.com/ipfs/boxo v0.17.1-0.20240112124340-bcb321c857c5/go.mod h1:pIZgTWdm3k3pLF9Uq6MB8JEcW07UDwNJjlXW1HELW80=
345 +github.com/ipfs/boxo v0.17.1-0.20240124092521-3d57bce7998c h1:A18UHDQ4V2Ai6/YsrH7kfGjA1r5SrwjQR1Lqiq68YQU=
346 +github.com/ipfs/boxo v0.17.1-0.20240124092521-3d57bce7998c/go.mod h1:pIZgTWdm3k3pLF9Uq6MB8JEcW07UDwNJjlXW1HELW80=
347 github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=
348 github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM=
349 github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
test/sharness/t0112-gateway-cors.sh
+6 -4
@@ -141,9 +141,11 @@ test_expect_success "Assert the default API.HTTPHeaders config is empty" '
141 test_expect_success "Default CORS GET to {gw}/api/v0" '
142 curl -svX GET -H "Origin: https://example.com" "http://127.0.0.1:$GWAY_PORT/api/v0/cat?arg=$thash" >/dev/null 2>curl_output
143 '
144 -test_expect_success "Default CORS GET response from {gw}/api/v0 is 403 Forbidden and has no CORS headers" '
144 +# HTTP 403 is returned because Kubo has additional protections on top of regular CORS,
145 +# namely it only allows browser requests with localhost Origin header.
146 +test_expect_success "Default CORS GET response from {gw}/api/v0 is 403 Forbidden and has regular CORS headers" '
147 test_should_contain "HTTP/1.1 403 Forbidden" curl_output &&
146 - test_should_not_contain "< Access-Control-" curl_output
148 + test_should_contain "< Access-Control-" curl_output
149 '
150
151 # HTTP OPTIONS Request
@@ -151,8 +153,8 @@ test_expect_success "Default OPTIONS to {gw}/api/v0" '
153 curl -svX OPTIONS -H "Origin: https://example.com" "http://127.0.0.1:$GWAY_PORT/api/v0/cat?arg=$thash" 2>curl_output
154 '
155 # OPTIONS Response from the API should NOT contain CORS headers
154 -test_expect_success "OPTIONS response from {gw}/api/v0 has no CORS header" '
155 - test_should_not_contain "< Access-Control-" curl_output
156 +test_expect_success "OPTIONS response from {gw}/api/v0 has CORS headers" '
157 + test_should_contain "< Access-Control-" curl_output
158 '
159
160 test_kill_ipfs_daemon