From 989df62a2b17316aa9271ce87eedd4c2b966491c Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 13 Feb 2024 12:31:12 +0100 Subject: [PATCH] test: add trustless e2e test --- go.mod | 3 +- handler_test.go | 109 ++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 6 +-- 3 files changed, 113 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index b401299..d2803c7 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( github.com/mitchellh/go-server-timing v1.0.1 github.com/mr-tron/base58 v1.2.0 github.com/multiformats/go-multiaddr v0.12.2 + github.com/multiformats/go-multicodec v0.9.0 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/prometheus/client_golang v1.18.0 github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 @@ -126,7 +127,6 @@ require ( github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect - github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect @@ -153,6 +153,7 @@ require ( github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect github.com/whyrusleeping/cbor-gen v0.0.0-20240109153615-66e95c3e8a87 // indirect + github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.opentelemetry.io/contrib/propagators/aws v1.23.0 // indirect diff --git a/handler_test.go b/handler_test.go index 959bc31..8dd709e 100644 --- a/handler_test.go +++ b/handler_test.go @@ -1,11 +1,22 @@ package main import ( + "bytes" + "context" "net/http" "net/http/httptest" "testing" + chunker "github.com/ipfs/boxo/chunker" + "github.com/ipfs/boxo/ipld/merkledag" + "github.com/ipfs/boxo/ipld/unixfs/importer/balanced" + uih "github.com/ipfs/boxo/ipld/unixfs/importer/helpers" + util "github.com/ipfs/boxo/util" + "github.com/ipfs/go-cid" + ic "github.com/libp2p/go-libp2p/core/crypto" + "github.com/multiformats/go-multicodec" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) type rpcRedirectTest struct { @@ -85,3 +96,101 @@ func TestRPCNotImplemented(t *testing.T) { assert.Equal(t, http.StatusNotImplemented, resp.Code) } } + +func mustTestServer(t *testing.T, cfg Config) (*httptest.Server, *Node) { + cfg.DataDir = t.TempDir() + cfg.BlockstoreType = "flatfs" + + ctx := context.Background() + + sr := util.NewTimeSeededRand() + sk, _, err := ic.GenerateKeyPairWithReader(ic.Ed25519, 2048, sr) + require.NoError(t, err) + + cdns := newCachedDNS(dnsCacheRefreshInterval) + + t.Cleanup(func() { + _ = cdns.Close() + }) + + gnd, err := Setup(ctx, cfg, sk, cdns) + if err != nil { + require.NoError(t, err) + } + + handler, err := setupGatewayHandler(cfg, gnd) + if err != nil { + require.NoError(t, err) + } + + ts := httptest.NewServer(handler) + + return ts, gnd +} + +func mustAddFile(t *testing.T, gnd *Node, content []byte) cid.Cid { + dsrv := merkledag.NewDAGService(gnd.bsrv) + + // Create a UnixFS graph from our file, parameters described here but can be visualized at https://dag.ipfs.tech/ + ufsImportParams := uih.DagBuilderParams{ + Maxlinks: uih.DefaultLinksPerBlock, // Default max of 174 links per block + RawLeaves: true, // Leave the actual file bytes untouched instead of wrapping them in a dag-pb protobuf wrapper + CidBuilder: cid.V1Builder{ // Use CIDv1 for all links + Codec: uint64(multicodec.DagPb), + MhType: uint64(multicodec.Sha2_256), // Use SHA2-256 as the hash function + MhLength: -1, // Use the default hash length for the given hash function (in this case 256 bits) + }, + Dagserv: dsrv, + NoCopy: false, + } + ufsBuilder, err := ufsImportParams.New(chunker.NewSizeSplitter(bytes.NewReader(content), chunker.DefaultBlockSize)) // Split the file up into fixed sized 256KiB chunks + require.NoError(t, err) + + nd, err := balanced.Layout(ufsBuilder) // Arrange the graph with a balanced layout + require.NoError(t, err) + + return nd.Cid() +} + +func TestTrustless(t *testing.T) { + t.Parallel() + + ts, gnd := mustTestServer(t, Config{ + TrustlessGatewayDomains: []string{"trustless.com"}, + }) + + content := "hello world" + cid := mustAddFile(t, gnd, []byte(content)) + url := ts.URL + "/ipfs/" + cid.String() + + t.Run("Non-trustless request returns 406", func(t *testing.T) { + req, err := http.NewRequest(http.MethodGet, url, nil) + require.NoError(t, err) + req.Host = "trustless.com" + + res, err := http.DefaultClient.Do(req) + assert.NoError(t, err) + assert.Equal(t, http.StatusNotAcceptable, res.StatusCode) + }) + + t.Run("Trustless request with query parameter returns 200", func(t *testing.T) { + req, err := http.NewRequest(http.MethodGet, url+"?format=raw", nil) + require.NoError(t, err) + req.Host = "trustless.com" + + res, err := http.DefaultClient.Do(req) + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) + }) + + t.Run("Trustless request with accept header returns 200", func(t *testing.T) { + req, err := http.NewRequest(http.MethodGet, url, nil) + require.NoError(t, err) + req.Host = "trustless.com" + req.Header.Set("Accept", "application/vnd.ipld.raw") + + res, err := http.DefaultClient.Do(req) + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) + }) +} diff --git a/main.go b/main.go index 92dc1dd..90bd0e0 100644 --- a/main.go +++ b/main.go @@ -46,12 +46,12 @@ only websites, but any supported content-addressed Merkle-DAG), in formats that are suitable for verification client-side (i.e. CAR files). Rainbow is optimized to perform the tasks of a gateway and only that, making -opinionated choices on the configration and setup of internal +opinionated choices on the configuration and setup of internal components. Rainbow aims to serve production environments, where gateways are deployed as a public service meant to be accessible by anyone. Rainbow acts as a client to the IPFS network and does not serve or provide content to it. Rainbow cannot be used to store or pin IPFS content, other than that -temporailly served over HTTP. Rainbow is just a gateway. +temporarily served over HTTP. Rainbow is just a gateway. Persistent configuration and data is stored in $RAINBOW_DATADIR (by default, the folder in which rainbow is run). @@ -73,7 +73,6 @@ Generate an identity seed and launch a gateway: ` app.Flags = []cli.Flag{ - &cli.StringFlag{ Name: "datadir", Value: "", @@ -122,7 +121,6 @@ Generate an identity seed and launch a gateway: EnvVars: []string{"RAINBOW_CTL_LISTEN_ADDRESS"}, Usage: "Listen address for the management api and metrics", }, - &cli.IntFlag{ Name: "connmgr-low", Value: 100,