diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 12b3f4d9cccc..b96a10ad66e6 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -66,7 +66,6 @@ const ( routingOptionAutoKwd = "auto" unencryptTransportKwd = "disable-transport-encryption" unrestrictedAPIAccessKwd = "unrestricted-api" - writableKwd = "writable" enablePubSubKwd = "enable-pubsub-experiment" enableIPNSPubSubKwd = "enable-namesys-pubsub" enableMultiplexKwd = "enable-mplex-experiment" @@ -162,7 +161,6 @@ Headers. cmds.StringOption(initProfileOptionKwd, "Configuration profiles to apply for --init. See ipfs init --help for more"), cmds.StringOption(routingOptionKwd, "Overrides the routing option").WithDefault(routingOptionDefaultKwd), cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem using FUSE (experimental)"), - cmds.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)"), cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."), cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."), cmds.BoolOption(unrestrictedAPIAccessKwd, "Allow API access to unlisted hashes"), @@ -683,9 +681,9 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error // only the webui objects are allowed. // if you know what you're doing, go ahead and pass --unrestricted-api. unrestricted, _ := req.Options[unrestrictedAPIAccessKwd].(bool) - gatewayOpt := corehttp.GatewayOption(false, corehttp.WebUIPaths...) + gatewayOpt := corehttp.GatewayOption(corehttp.WebUIPaths...) if unrestricted { - gatewayOpt = corehttp.GatewayOption(true, "/ipfs", "/ipns") + gatewayOpt = corehttp.GatewayOption("/ipfs", "/ipns") } var opts = []corehttp.ServeOption{ @@ -789,9 +787,8 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e return nil, fmt.Errorf("serveHTTPGateway: GetConfig() failed: %s", err) } - writable, writableOptionFound := req.Options[writableKwd].(bool) - if !writableOptionFound { - writable = cfg.Gateway.Writable + if cfg.Gateway.Writable { + return nil, fmt.Errorf("serveHTTPGateway: writable gateways are no longer supported, please remove .Gateway.Writable from your configuration file") } listeners, err := sockets.TakeListeners("io.ipfs.gateway") @@ -824,13 +821,9 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e } // we might have listened to /tcp/0 - let's see what we are listing on - gwType := "readonly" - if writable { - gwType = "writable" - } for _, listener := range listeners { - fmt.Printf("Gateway (%s) server listening on %s\n", gwType, listener.Multiaddr()) + fmt.Printf("Gateway (readonly) server listening on %s\n", listener.Multiaddr()) } cmdctx := *cctx @@ -839,7 +832,7 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e var opts = []corehttp.ServeOption{ corehttp.MetricsCollectionOption("gateway"), corehttp.HostnameOption(), - corehttp.GatewayOption(writable, "/ipfs", "/ipns"), + corehttp.GatewayOption("/ipfs", "/ipns"), corehttp.VersionOption(), corehttp.CheckVersionOption(), corehttp.CommandsROOption(cmdctx), diff --git a/cmd/ipfswatch/main.go b/cmd/ipfswatch/main.go index 06215687c05f..2c333fc2336a 100644 --- a/cmd/ipfswatch/main.go +++ b/cmd/ipfswatch/main.go @@ -94,7 +94,7 @@ func run(ipfsPath, watchPath string) error { if *http { addr := "/ip4/127.0.0.1/tcp/5001" var opts = []corehttp.ServeOption{ - corehttp.GatewayOption(true, "/ipfs", "/ipns"), + corehttp.GatewayOption("/ipfs", "/ipns"), corehttp.WebUIOption, corehttp.CommandsOption(cmdCtx(node, ipfsPath)), } diff --git a/config/gateway.go b/config/gateway.go index ad01b263b366..0e76bffdc018 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -38,8 +38,8 @@ type Gateway struct { // should be redirected. RootRedirect string - // Writable enables PUT/POST request handling by this gateway. Usually, - // writing is done through the API, not the gateway. + // REMOVED: Writable enables PUT/POST request handling by this gateway. + // Usually, writing is done through the API, not the gateway. Writable bool // PathPrefixes was removed: https://github.com/ipfs/go-ipfs/issues/7702 diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go index d5eccf73c275..5f260978d672 100644 --- a/core/corehttp/gateway.go +++ b/core/corehttp/gateway.go @@ -1,12 +1,19 @@ package corehttp import ( + "context" "fmt" + "io" "net" "net/http" + cid "github.com/ipfs/go-cid" + ipld "github.com/ipfs/go-ipld-format" + "github.com/ipfs/go-libipfs/files" "github.com/ipfs/go-libipfs/gateway" + iface "github.com/ipfs/interface-go-ipfs-core" options "github.com/ipfs/interface-go-ipfs-core/options" + "github.com/ipfs/interface-go-ipfs-core/path" version "github.com/ipfs/kubo" core "github.com/ipfs/kubo/core" coreapi "github.com/ipfs/kubo/core/coreapi" @@ -14,14 +21,14 @@ import ( "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) -func GatewayOption(writable bool, paths ...string) ServeOption { +func GatewayOption(paths ...string) ServeOption { return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) { cfg, err := n.Repo.Config() if err != nil { return nil, err } - api, err := coreapi.NewCoreAPI(n, options.Api.FetchBlocks(!cfg.Gateway.NoFetch)) + nodeAPI, err := coreapi.NewCoreAPI(n, options.Api.FetchBlocks(!cfg.Gateway.NoFetch)) if err != nil { return nil, err } @@ -33,16 +40,21 @@ func GatewayOption(writable bool, paths ...string) ServeOption { gateway.AddAccessControlHeaders(headers) - offlineAPI, err := api.WithOptions(options.Api.Offline(true)) + offlineNodeAPI, err := nodeAPI.WithOptions(options.Api.Offline(true)) if err != nil { return nil, err } - gateway := gateway.NewHandler(gateway.Config{ - Headers: headers, - Writable: writable, - }, api, offlineAPI) + gatewayCfg := gateway.Config{ + Headers: headers, + } + + gwAPI := &gatewayAPI{ + node: nodeAPI, + offlineNode: offlineNodeAPI, + } + gateway := gateway.NewHandler(gatewayCfg, gwAPI) gateway = otelhttp.NewHandler(gateway, "Gateway.Request") for _, p := range paths { @@ -62,3 +74,36 @@ func VersionOption() ServeOption { return mux, nil } } + +type gatewayAPI struct { + node iface.CoreAPI + offlineNode iface.CoreAPI +} + +func (gw *gatewayAPI) GetUnixFs(ctx context.Context, pth path.Path) (files.Node, error) { + return gw.node.Unixfs().Get(ctx, pth) +} + +func (gw *gatewayAPI) LsUnixFs(ctx context.Context, pth path.Path, opts ...options.UnixfsLsOption) (<-chan iface.DirEntry, error) { + return gw.node.Unixfs().Ls(ctx, pth, opts...) +} + +func (gw *gatewayAPI) GetBlock(ctx context.Context, pth path.Path) (io.Reader, error) { + return gw.node.Block().Get(ctx, pth) +} + +func (gw *gatewayAPI) StatBlockOffline(ctx context.Context, pth path.Path) (iface.BlockStat, error) { + return gw.offlineNode.Block().Stat(ctx, pth) +} + +func (gw *gatewayAPI) GetNode(ctx context.Context, cid cid.Cid) (ipld.Node, error) { + return gw.node.Dag().Get(ctx, cid) +} + +func (gw *gatewayAPI) GetRouting(ctx context.Context, k string) ([]byte, error) { + return gw.node.Routing().Get(ctx, k) +} + +func (gw *gatewayAPI) ResolvePath(ctx context.Context, pth path.Path) (path.Resolved, error) { + return gw.node.ResolvePath(ctx, pth) +} diff --git a/core/corehttp/gateway_test.go b/core/corehttp/gateway_test.go index 49fa519fb3d6..94eda2d778e4 100644 --- a/core/corehttp/gateway_test.go +++ b/core/corehttp/gateway_test.go @@ -130,7 +130,7 @@ func newTestServerAndNode(t *testing.T, ns mockNamesys) (*httptest.Server, iface dh.Handler, err = makeHandler(n, ts.Listener, HostnameOption(), - GatewayOption(false, "/ipfs", "/ipns"), + GatewayOption("/ipfs", "/ipns"), VersionOption(), ) if err != nil { diff --git a/docs/config.md b/docs/config.md index 995872c4f37f..98ca81b81506 100644 --- a/docs/config.md +++ b/docs/config.md @@ -682,11 +682,7 @@ Type: `string` (url) ### `Gateway.Writable` -A boolean to configure whether the gateway is writeable or not. - -Default: `false` - -Type: `bool` +**REMOVED**: Kubo no longer provides a Writable Gateway. ### `Gateway.PathPrefixes` diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod index a74bfbf3e03d..8e4006156289 100644 --- a/docs/examples/kubo-as-a-library/go.mod +++ b/docs/examples/kubo-as-a-library/go.mod @@ -7,7 +7,7 @@ go 1.18 replace github.com/ipfs/kubo => ./../../.. require ( - github.com/ipfs/go-libipfs v0.4.1-0.20230130233950-a005a5006496 + github.com/ipfs/go-libipfs v0.4.1-0.20230131164115-b4a01af26d08 github.com/ipfs/interface-go-ipfs-core v0.10.0 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000 github.com/libp2p/go-libp2p v0.24.2 diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum index eb37654f786e..bd1699b7b3aa 100644 --- a/docs/examples/kubo-as-a-library/go.sum +++ b/docs/examples/kubo-as-a-library/go.sum @@ -548,8 +548,8 @@ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2 github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A= github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= -github.com/ipfs/go-libipfs v0.4.1-0.20230130233950-a005a5006496 h1:RVI31GQCFODREpasIFyVFkS6PjJT2bMwr/Bgr9Ryql4= -github.com/ipfs/go-libipfs v0.4.1-0.20230130233950-a005a5006496/go.mod h1:AAPvZADZ80i+QhGCWNWCsx8IGY0t9C+IBEngLeYtySY= +github.com/ipfs/go-libipfs v0.4.1-0.20230131164115-b4a01af26d08 h1:nOCkGmyfl4m77P+lWR83d3jsFS0ek+kYxmUuONGMEe8= +github.com/ipfs/go-libipfs v0.4.1-0.20230131164115-b4a01af26d08/go.mod h1:P6YEhRwAljcifKAGL01RobOTfSfyFacr0F8wiJNz2uE= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= diff --git a/go.mod b/go.mod index 5edf9f68a467..e0d1266393f9 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/ipfs/go-ipld-git v0.1.1 github.com/ipfs/go-ipld-legacy v0.1.1 github.com/ipfs/go-ipns v0.3.0 - github.com/ipfs/go-libipfs v0.4.1-0.20230130233950-a005a5006496 + github.com/ipfs/go-libipfs v0.4.1-0.20230131164115-b4a01af26d08 github.com/ipfs/go-log v1.0.5 github.com/ipfs/go-log/v2 v2.5.1 github.com/ipfs/go-merkledag v0.9.0 diff --git a/go.sum b/go.sum index fefe9bf71606..03d8bf754688 100644 --- a/go.sum +++ b/go.sum @@ -570,8 +570,8 @@ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2 github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A= github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= -github.com/ipfs/go-libipfs v0.4.1-0.20230130233950-a005a5006496 h1:RVI31GQCFODREpasIFyVFkS6PjJT2bMwr/Bgr9Ryql4= -github.com/ipfs/go-libipfs v0.4.1-0.20230130233950-a005a5006496/go.mod h1:AAPvZADZ80i+QhGCWNWCsx8IGY0t9C+IBEngLeYtySY= +github.com/ipfs/go-libipfs v0.4.1-0.20230131164115-b4a01af26d08 h1:nOCkGmyfl4m77P+lWR83d3jsFS0ek+kYxmUuONGMEe8= +github.com/ipfs/go-libipfs v0.4.1-0.20230131164115-b4a01af26d08/go.mod h1:P6YEhRwAljcifKAGL01RobOTfSfyFacr0F8wiJNz2uE= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= diff --git a/test/sharness/lib/test-lib.sh b/test/sharness/lib/test-lib.sh index 3aecaec994b7..8b57fb1a1bdc 100644 --- a/test/sharness/lib/test-lib.sh +++ b/test/sharness/lib/test-lib.sh @@ -214,13 +214,6 @@ test_init_ipfs() { } -test_config_ipfs_gateway_writable() { - test_expect_success "prepare config -- gateway writable" ' - test_config_set --bool Gateway.Writable true || - test_fsh cat "\"$IPFS_PATH/config\"" - ' -} - test_wait_for_file() { loops=$1 delay=$2 diff --git a/test/sharness/t0111-gateway-writeable.sh b/test/sharness/t0111-gateway-writeable.sh deleted file mode 100755 index 53d4fc1aa408..000000000000 --- a/test/sharness/t0111-gateway-writeable.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2014 Christian Couder -# MIT Licensed; see the LICENSE file in this repository. -# - -test_description="Test HTTP Gateway (Writable)" - -. lib/test-lib.sh - -test_init_ipfs - -test_launch_ipfs_daemon --writable -test_expect_success "ipfs daemon --writable overrides config" ' - curl -v -X POST http://$GWAY_ADDR/ipfs/ 2> outfile && - grep "HTTP/1.1 201 Created" outfile && - grep "Location: /ipfs/QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH" outfile -' -test_kill_ipfs_daemon - -test_config_ipfs_gateway_writable -test_launch_ipfs_daemon --writable=false -test_expect_success "ipfs daemon --writable=false overrides Writable=true config" ' - curl -v -X POST http://$GWAY_ADDR/ipfs/ 2> outfile && - grep "HTTP/1.1 405 Method Not Allowed" outfile -' -test_kill_ipfs_daemon -test_launch_ipfs_daemon - -port=$GWAY_PORT - -test_expect_success "ipfs daemon up" ' - pollEndpoint -host $GWAY_MADDR -v -tout=1s -tries=60 2>poll_apierr > poll_apiout || - test_fsh cat poll_apierr || test_fsh cat poll_apiout -' - -test_expect_success "HTTP gateway gives access to sample file" ' - curl -s -o welcome "http://$GWAY_ADDR/ipfs/$HASH_WELCOME_DOCS/readme" && - grep "Hello and Welcome to IPFS!" welcome -' - -test_expect_success "HTTP POST file gives Hash" ' - echo "$RANDOM" >infile && - URL="http://127.0.0.1:$port/ipfs/" && - curl -svX POST --data-binary @infile "$URL" 2>curl_post.out && - grep "HTTP/1.1 201 Created" curl_post.out && - LOCATION=$(grep Location curl_post.out) && - HASH=$(echo $LOCATION | cut -d":" -f2- |tr -d " \n\r") -' - -test_expect_success "We can HTTP GET file just created" ' - URL="http://127.0.0.1:${port}${HASH}" && - curl -so outfile "$URL" && - test_cmp infile outfile -' - -test_expect_success "We got the correct hash" ' - ADD_HASH="/ipfs/$(ipfs add -q infile)" && - test "x$ADD_HASH" = "x$HASH" || test_fsh echo "$ADD_HASH != $HASH" -' - -test_expect_success "HTTP GET empty directory" ' - URL="http://127.0.0.1:$port/ipfs/$HASH_EMPTY_DIR/" && - echo "GET $URL" && - curl -so outfile "$URL" 2>curl_getEmpty.out && - cat outfile | tr -s "\n" " " | grep "Index of /ipfs/$HASH_EMPTY_DIR" -' - -test_expect_success "HTTP PUT file to construct a hierarchy" ' - echo "$RANDOM" >infile && - URL="http://127.0.0.1:$port/ipfs/$HASH_EMPTY_DIR/test.txt" && - echo "PUT $URL" && - curl -svX PUT --data-binary @infile "$URL" 2>curl_put.out && - grep "HTTP/1.1 201 Created" curl_put.out && - LOCATION=$(grep Location curl_put.out) && - HASH=$(expr "$LOCATION" : "< Location: /ipfs/\(.*\)/test.txt") -' - -test_expect_success "We can HTTP GET file just created" ' - URL="http://127.0.0.1:$port/ipfs/$HASH/test.txt" && - echo "GET $URL" && - curl -so outfile "$URL" && - test_cmp infile outfile -' - -test_expect_success "HTTP PUT file to append to existing hierarchy" ' - echo "$RANDOM" >infile2 && - URL="http://127.0.0.1:$port/ipfs/$HASH/test/test.txt" && - echo "PUT $URL" && - curl -svX PUT --data-binary @infile2 "$URL" 2>curl_putAgain.out && - grep "HTTP/1.1 201 Created" curl_putAgain.out && - LOCATION=$(grep Location curl_putAgain.out) && - HASH=$(expr "$LOCATION" : "< Location: /ipfs/\(.*\)/test/test.txt") -' - - -test_expect_success "We can HTTP GET file just updated" ' - URL="http://127.0.0.1:$port/ipfs/$HASH/test/test.txt" && - echo "GET $URL" && - curl -svo outfile2 "$URL" 2>curl_getAgain.out && - test_cmp infile2 outfile2 -' - -test_expect_success "HTTP PUT to replace a directory" ' - echo "$RANDOM" >infile3 && - URL="http://127.0.0.1:$port/ipfs/$HASH/test" && - echo "PUT $URL" && - curl -svX PUT --data-binary @infile3 "$URL" 2>curl_putOverDirectory.out && - grep "HTTP/1.1 201 Created" curl_putOverDirectory.out && - LOCATION=$(grep Location curl_putOverDirectory.out) && - HASH=$(expr "$LOCATION" : "< Location: /ipfs/\(.*\)/test") -' - -test_expect_success "We can HTTP GET file just put over a directory" ' - URL="http://127.0.0.1:$port/ipfs/$HASH/test" && - echo "GET $URL" && - curl -svo outfile3 "$URL" 2>curl_getOverDirectory.out && - test_cmp infile3 outfile3 -' - -test_expect_success "HTTP PUT to /ipns fails" ' - PEERID=`ipfs id --format=""` && - URL="http://127.0.0.1:$port/ipns/$PEERID/test.txt" && - echo "PUT $URL" && - curl -svX PUT --data-binary @infile1 "$URL" 2>curl_putIpns.out && - grep "HTTP/1.1 400 Bad Request" curl_putIpns.out -' - - -test_kill_ipfs_daemon - -test_done