diff --git a/gateway/gateway_test.go b/gateway/gateway_test.go
index f878cb631..ae1a9bce6 100644
--- a/gateway/gateway_test.go
+++ b/gateway/gateway_test.go
@@ -3,17 +3,43 @@ package gateway
import (
"context"
"errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ gopath "path"
+ "regexp"
"strings"
+ "testing"
- cid "github.com/ipfs/go-cid"
+ "github.com/ipfs/go-blockservice"
+ "github.com/ipfs/go-cid"
+ bsfetcher "github.com/ipfs/go-fetcher/impl/blockservice"
+ blockstore "github.com/ipfs/go-ipfs-blockstore"
+ offline "github.com/ipfs/go-ipfs-exchange-offline"
+ format "github.com/ipfs/go-ipld-format"
"github.com/ipfs/go-libipfs/blocks"
"github.com/ipfs/go-libipfs/files"
+ "github.com/ipfs/go-merkledag"
"github.com/ipfs/go-namesys"
+ "github.com/ipfs/go-namesys/resolve"
path "github.com/ipfs/go-path"
+ "github.com/ipfs/go-path/resolver"
+ "github.com/ipfs/go-unixfs"
+ ufile "github.com/ipfs/go-unixfs/file"
+ uio "github.com/ipfs/go-unixfs/io"
+ "github.com/ipfs/go-unixfsnode"
iface "github.com/ipfs/interface-go-ipfs-core"
nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
ipath "github.com/ipfs/interface-go-ipfs-core/path"
+ carblockstore "github.com/ipld/go-car/v2/blockstore"
+ dagpb "github.com/ipld/go-codec-dagpb"
+ "github.com/ipld/go-ipld-prime"
+ "github.com/ipld/go-ipld-prime/node/basicnode"
+ "github.com/ipld/go-ipld-prime/schema"
"github.com/libp2p/go-libp2p/core/crypto"
+ "github.com/libp2p/go-libp2p/core/routing"
)
type mockNamesys map[string]path.Path
@@ -60,44 +86,681 @@ func (m mockNamesys) GetResolver(subs string) (namesys.Resolver, bool) {
return nil, false
}
-type mockApi struct {
- ns mockNamesys
+type mockAPI struct {
+ blockStore blockstore.Blockstore
+ blockService blockservice.BlockService
+ dagService format.DAGService
+ resolver resolver.Resolver
+ namesys mockNamesys
}
-func newMockApi() *mockApi {
- return &mockApi{
- ns: mockNamesys{},
+func newMockAPI(t *testing.T) (*mockAPI, cid.Cid) {
+ r, err := os.Open("./testdata/fixtures.car")
+ if err != nil {
+ t.Fatal(err)
}
+
+ blockStore, err := carblockstore.NewReadOnly(r, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Cleanup(func() {
+ blockStore.Close()
+ r.Close()
+ })
+
+ cids, err := blockStore.Roots()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(cids) != 1 {
+ t.Fatal(fmt.Errorf("car has %d roots, expected 1", len(cids)))
+ }
+
+ blockService := blockservice.New(blockStore, offline.Exchange(blockStore))
+ dagService := merkledag.NewDAGService(blockService)
+
+ fetcherConfig := bsfetcher.NewFetcherConfig(blockService)
+ fetcherConfig.PrototypeChooser = dagpb.AddSupportToChooser(func(lnk ipld.Link, lnkCtx ipld.LinkContext) (ipld.NodePrototype, error) {
+ if tlnkNd, ok := lnkCtx.LinkNode.(schema.TypedLinkNode); ok {
+ return tlnkNd.LinkTargetNodePrototype(), nil
+ }
+ return basicnode.Prototype.Any, nil
+ })
+ fetcher := fetcherConfig.WithReifier(unixfsnode.Reify)
+ resolver := resolver.NewBasicResolver(fetcher)
+
+ return &mockAPI{
+ blockStore: blockService.Blockstore(),
+ blockService: blockService,
+ dagService: dagService,
+ resolver: resolver,
+ namesys: mockNamesys{},
+ }, cids[0]
}
-func (m *mockApi) GetUnixFsNode(context.Context, ipath.Resolved) (files.Node, error) {
- return nil, errors.New("not implemented")
+func (api *mockAPI) GetUnixFsNode(ctx context.Context, p ipath.Resolved) (files.Node, error) {
+ nd, err := api.resolveNode(ctx, p)
+ if err != nil {
+ return nil, err
+ }
+
+ return ufile.NewUnixfsFile(ctx, api.dagService, nd)
}
-func (m *mockApi) LsUnixFsDir(context.Context, ipath.Resolved) (<-chan iface.DirEntry, error) {
- return nil, errors.New("not implemented")
+func (api *mockAPI) LsUnixFsDir(ctx context.Context, p ipath.Resolved) (<-chan iface.DirEntry, error) {
+ node, err := api.resolveNode(ctx, p)
+ if err != nil {
+ return nil, err
+ }
+
+ dir, err := uio.NewDirectoryFromNode(api.dagService, node)
+ if err != nil {
+ return nil, err
+ }
+
+ out := make(chan iface.DirEntry, uio.DefaultShardWidth)
+
+ go func() {
+ defer close(out)
+ for l := range dir.EnumLinksAsync(ctx) {
+ select {
+ case out <- api.processLink(ctx, l):
+ case <-ctx.Done():
+ return
+ }
+ }
+ }()
+
+ return out, nil
}
-func (m *mockApi) GetBlock(context.Context, cid.Cid) (blocks.Block, error) {
- return nil, errors.New("not implemented")
+func (api *mockAPI) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) {
+ return api.blockService.GetBlock(ctx, c)
+}
+
+func (api *mockAPI) GetIPNSRecord(ctx context.Context, c cid.Cid) ([]byte, error) {
+ return nil, routing.ErrNotSupported
}
-func (m *mockApi) GetIPNSRecord(context.Context, cid.Cid) ([]byte, error) {
+func (api *mockAPI) GetDNSLinkRecord(ctx context.Context, hostname string) (ipath.Path, error) {
+ if api.namesys != nil {
+ p, err := api.namesys.Resolve(ctx, "/ipns/"+hostname, nsopts.Depth(1))
+ if err == namesys.ErrResolveRecursion {
+ err = nil
+ }
+ return ipath.New(p.String()), err
+ }
+
return nil, errors.New("not implemented")
}
-func (m *mockApi) GetDNSLinkRecord(ctx context.Context, hostname string) (ipath.Path, error) {
- p, err := m.ns.Resolve(ctx, "/ipns/"+hostname, nsopts.Depth(1))
- if err == namesys.ErrResolveRecursion {
- err = nil
+func (api *mockAPI) IsCached(ctx context.Context, p ipath.Path) bool {
+ rp, err := api.ResolvePath(ctx, p)
+ if err != nil {
+ return false
}
- return ipath.New(p.String()), err
+
+ has, _ := api.blockStore.Has(ctx, rp.Cid())
+ return has
}
-func (m *mockApi) IsCached(context.Context, ipath.Path) bool {
- return false
+func (api *mockAPI) ResolvePath(ctx context.Context, ip ipath.Path) (ipath.Resolved, error) {
+ if _, ok := ip.(ipath.Resolved); ok {
+ return ip.(ipath.Resolved), nil
+ }
+
+ err := ip.IsValid()
+ if err != nil {
+ return nil, err
+ }
+
+ p := path.Path(ip.String())
+ if p.Segments()[0] == "ipns" {
+ p, err = resolve.ResolveIPNS(ctx, api.namesys, p)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if p.Segments()[0] != "ipfs" {
+ return nil, fmt.Errorf("unsupported path namespace: %s", ip.Namespace())
+ }
+
+ node, rest, err := api.resolver.ResolveToLastNode(ctx, p)
+ if err != nil {
+ return nil, err
+ }
+
+ root, err := cid.Parse(p.Segments()[1])
+ if err != nil {
+ return nil, err
+ }
+
+ return ipath.NewResolvedPath(p, node, root, gopath.Join(rest...)), nil
}
-func (m *mockApi) ResolvePath(context.Context, ipath.Path) (ipath.Resolved, error) {
- return nil, errors.New("not implemented")
+func (api *mockAPI) resolveNode(ctx context.Context, p ipath.Path) (format.Node, error) {
+ rp, err := api.ResolvePath(ctx, p)
+ if err != nil {
+ return nil, err
+ }
+
+ node, err := api.dagService.Get(ctx, rp.Cid())
+ if err != nil {
+ return nil, fmt.Errorf("get node: %w", err)
+ }
+ return node, nil
+}
+
+func (api *mockAPI) processLink(ctx context.Context, result unixfs.LinkResult) iface.DirEntry {
+ if result.Err != nil {
+ return iface.DirEntry{Err: result.Err}
+ }
+
+ link := iface.DirEntry{
+ Name: result.Link.Name,
+ Cid: result.Link.Cid,
+ }
+
+ switch link.Cid.Type() {
+ case cid.Raw:
+ link.Type = iface.TFile
+ link.Size = result.Link.Size
+ case cid.DagProtobuf:
+ link.Size = result.Link.Size
+ }
+
+ return link
+}
+
+func doWithoutRedirect(req *http.Request) (*http.Response, error) {
+ tag := "without-redirect"
+ c := &http.Client{
+ CheckRedirect: func(req *http.Request, via []*http.Request) error {
+ return errors.New(tag)
+ },
+ }
+ res, err := c.Do(req)
+ if err != nil && !strings.Contains(err.Error(), tag) {
+ return nil, err
+ }
+ return res, nil
+}
+
+func newTestServerAndNode(t *testing.T, ns mockNamesys) (*httptest.Server, *mockAPI, cid.Cid) {
+ api, root := newMockAPI(t)
+
+ config := Config{Headers: map[string][]string{}}
+ AddAccessControlHeaders(config.Headers)
+
+ handler := NewHandler(config, api)
+ mux := http.NewServeMux()
+ mux.Handle("/ipfs/", handler)
+ mux.Handle("/ipns/", handler)
+ handler = WithHostname(mux, api, map[string]*Specification{}, false)
+
+ ts := httptest.NewServer(handler)
+ t.Cleanup(func() { ts.Close() })
+
+ return ts, api, root
+}
+
+func matchPathOrBreadcrumbs(s string, expected string) bool {
+ matched, _ := regexp.MatchString("Index of(\n|\r\n)[\t ]*"+regexp.QuoteMeta(expected), s)
+ return matched
+}
+
+func TestGatewayGet(t *testing.T) {
+ ts, api, root := newTestServerAndNode(t, nil)
+ t.Logf("test server url: %s", ts.URL)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ k, err := api.ResolvePath(ctx, ipath.Join(ipath.IpfsPath(root), t.Name(), "fnord"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ api.namesys["/ipns/example.com"] = path.FromCid(k.Cid())
+ api.namesys["/ipns/working.example.com"] = path.FromString(k.String())
+ api.namesys["/ipns/double.example.com"] = path.FromString("/ipns/working.example.com")
+ api.namesys["/ipns/triple.example.com"] = path.FromString("/ipns/double.example.com")
+ api.namesys["/ipns/broken.example.com"] = path.FromString("/ipns/" + k.Cid().String())
+ // We picked .man because:
+ // 1. It's a valid TLD.
+ // 2. Go treats it as the file extension for "man" files (even though
+ // nobody actually *uses* this extension, AFAIK).
+ //
+ // Unfortunately, this may not work on all platforms as file type
+ // detection is platform dependent.
+ api.namesys["/ipns/example.man"] = path.FromString(k.String())
+
+ t.Log(ts.URL)
+ for i, test := range []struct {
+ host string
+ path string
+ status int
+ text string
+ }{
+ {"127.0.0.1:8080", "/", http.StatusNotFound, "404 page not found\n"},
+ {"127.0.0.1:8080", "/" + k.Cid().String(), http.StatusNotFound, "404 page not found\n"},
+ {"127.0.0.1:8080", k.String(), http.StatusOK, "fnord"},
+ {"127.0.0.1:8080", "/ipns/nxdomain.example.com", http.StatusBadRequest, "ipfs resolve -r /ipns/nxdomain.example.com: " + namesys.ErrResolveFailed.Error() + "\n"},
+ {"127.0.0.1:8080", "/ipns/%0D%0A%0D%0Ahello", http.StatusBadRequest, "ipfs resolve -r /ipns/\\r\\n\\r\\nhello: " + namesys.ErrResolveFailed.Error() + "\n"},
+ {"127.0.0.1:8080", "/ipns/example.com", http.StatusOK, "fnord"},
+ {"example.com", "/", http.StatusOK, "fnord"},
+
+ {"working.example.com", "/", http.StatusOK, "fnord"},
+ {"double.example.com", "/", http.StatusOK, "fnord"},
+ {"triple.example.com", "/", http.StatusOK, "fnord"},
+ {"working.example.com", k.String(), http.StatusNotFound, "ipfs resolve -r /ipns/working.example.com" + k.String() + ": no link named \"ipfs\" under " + k.Cid().String() + "\n"},
+ {"broken.example.com", "/", http.StatusBadRequest, "ipfs resolve -r /ipns/broken.example.com/: " + namesys.ErrResolveFailed.Error() + "\n"},
+ {"broken.example.com", k.String(), http.StatusBadRequest, "ipfs resolve -r /ipns/broken.example.com" + k.String() + ": " + namesys.ErrResolveFailed.Error() + "\n"},
+ // This test case ensures we don't treat the TLD as a file extension.
+ {"example.man", "/", http.StatusOK, "fnord"},
+ } {
+ var c http.Client
+ r, err := http.NewRequest(http.MethodGet, ts.URL+test.path, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ r.Host = test.host
+ resp, err := c.Do(r)
+
+ urlstr := "http://" + test.host + test.path
+ if err != nil {
+ t.Errorf("error requesting %s: %s", urlstr, err)
+ continue
+ }
+ defer resp.Body.Close()
+ contentType := resp.Header.Get("Content-Type")
+ if contentType != "text/plain; charset=utf-8" {
+ t.Errorf("expected content type to be text/plain, got %s", contentType)
+ }
+ body, err := io.ReadAll(resp.Body)
+ if resp.StatusCode != test.status {
+ t.Errorf("(%d) got %d, expected %d from %s", i, resp.StatusCode, test.status, urlstr)
+ t.Errorf("Body: %s", body)
+ continue
+ }
+ if err != nil {
+ t.Fatalf("error reading response from %s: %s", urlstr, err)
+ }
+ if string(body) != test.text {
+ t.Errorf("unexpected response body from %s: expected %q; got %q", urlstr, test.text, body)
+ continue
+ }
+ }
+}
+
+func TestUriQueryRedirect(t *testing.T) {
+ ts, _, _ := newTestServerAndNode(t, mockNamesys{})
+
+ cid := "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"
+ for i, test := range []struct {
+ path string
+ status int
+ location string
+ }{
+ // - Browsers will send original URI in URL-escaped form
+ // - We expect query parameters to be persisted
+ // - We drop fragments, as those should not be sent by a browser
+ {"/ipfs/?uri=ipfs%3A%2F%2FQmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html%23header-%C4%85", http.StatusMovedPermanently, "/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
+ {"/ipfs/?uri=ipns%3A%2F%2Fexample.com%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html", http.StatusMovedPermanently, "/ipns/example.com/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
+ {"/ipfs/?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
+ {"/ipfs?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/?uri=ipfs://" + cid},
+ {"/ipfs/?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/" + cid},
+ {"/ipns/?uri=ipfs%3A%2F%2FQmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html%23header-%C4%85", http.StatusMovedPermanently, "/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
+ {"/ipns/?uri=ipns%3A%2F%2Fexample.com%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html", http.StatusMovedPermanently, "/ipns/example.com/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
+ {"/ipns?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/?uri=ipns://" + cid},
+ {"/ipns/?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/" + cid},
+ {"/ipns/?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
+ {"/ipfs/?uri=unsupported://" + cid, http.StatusBadRequest, ""},
+ {"/ipfs/?uri=invaliduri", http.StatusBadRequest, ""},
+ {"/ipfs/?uri=" + cid, http.StatusBadRequest, ""},
+ } {
+
+ r, err := http.NewRequest(http.MethodGet, ts.URL+test.path, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ resp, err := doWithoutRedirect(r)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != test.status {
+ t.Errorf("(%d) got %d, expected %d from %s", i, resp.StatusCode, test.status, ts.URL+test.path)
+ }
+
+ locHdr := resp.Header.Get("Location")
+ if locHdr != test.location {
+ t.Errorf("(%d) location header got %s, expected %s from %s", i, locHdr, test.location, ts.URL+test.path)
+ }
+ }
+}
+
+func TestIPNSHostnameRedirect(t *testing.T) {
+ ts, api, root := newTestServerAndNode(t, nil)
+ t.Logf("test server url: %s", ts.URL)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ k, err := api.ResolvePath(ctx, ipath.Join(ipath.IpfsPath(root), t.Name()))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Logf("k: %s\n", k)
+ api.namesys["/ipns/example.net"] = path.FromString(k.String())
+
+ // make request to directory containing index.html
+ req, err := http.NewRequest(http.MethodGet, ts.URL+"/foo", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Host = "example.net"
+
+ res, err := doWithoutRedirect(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // expect 301 redirect to same path, but with trailing slash
+ if res.StatusCode != 301 {
+ t.Errorf("status is %d, expected 301", res.StatusCode)
+ }
+ hdr := res.Header["Location"]
+ if len(hdr) < 1 {
+ t.Errorf("location header not present")
+ } else if hdr[0] != "/foo/" {
+ t.Errorf("location header is %v, expected /foo/", hdr[0])
+ }
+
+ // make request with prefix to directory containing index.html
+ req, err = http.NewRequest(http.MethodGet, ts.URL+"/foo", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Host = "example.net"
+
+ res, err = doWithoutRedirect(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // expect 301 redirect to same path, but with prefix and trailing slash
+ if res.StatusCode != 301 {
+ t.Errorf("status is %d, expected 301", res.StatusCode)
+ }
+ hdr = res.Header["Location"]
+ if len(hdr) < 1 {
+ t.Errorf("location header not present")
+ } else if hdr[0] != "/foo/" {
+ t.Errorf("location header is %v, expected /foo/", hdr[0])
+ }
+
+ // make sure /version isn't exposed
+ req, err = http.NewRequest(http.MethodGet, ts.URL+"/version", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Host = "example.net"
+
+ res, err = doWithoutRedirect(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if res.StatusCode != 404 {
+ t.Fatalf("expected a 404 error, got: %s", res.Status)
+ }
+}
+
+// Test directory listing on DNSLink website
+// (scenario when Host header is the same as URL hostname)
+// This is basic regression test: additional end-to-end tests
+// can be found in test/sharness/t0115-gateway-dir-listing.sh
+func TestIPNSHostnameBacklinks(t *testing.T) {
+ ts, api, root := newTestServerAndNode(t, nil)
+ t.Logf("test server url: %s", ts.URL)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ k, err := api.ResolvePath(ctx, ipath.Join(ipath.IpfsPath(root), t.Name()))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // create /ipns/example.net/foo/
+ k2, err := api.ResolvePath(ctx, ipath.Join(k, "foo? #<'"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ k3, err := api.ResolvePath(ctx, ipath.Join(k, "foo? #<'/bar"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Logf("k: %s\n", k)
+ api.namesys["/ipns/example.net"] = path.FromString(k.String())
+
+ // make request to directory listing
+ req, err := http.NewRequest(http.MethodGet, ts.URL+"/foo%3F%20%23%3C%27/", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Host = "example.net"
+
+ res, err := doWithoutRedirect(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // expect correct links
+ body, err := io.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("error reading response: %s", err)
+ }
+ s := string(body)
+ t.Logf("body: %s\n", string(body))
+
+ if !matchPathOrBreadcrumbs(s, "/ipns/example.net/foo? #<'") {
+ t.Fatalf("expected a path in directory listing")
+ }
+ if !strings.Contains(s, "") {
+ t.Fatalf("expected backlink in directory listing")
+ }
+ if !strings.Contains(s, "") {
+ t.Fatalf("expected file in directory listing")
+ }
+ if !strings.Contains(s, "") {
+ t.Fatalf("expected no backlink in directory listing of the root CID")
+ }
+ if !strings.Contains(s, "") {
+ t.Fatalf("expected file in directory listing")
+ }
+ if !strings.Contains(s, "example.net/foo? #<'/bar") {
+ t.Fatalf("expected a path in directory listing")
+ }
+ if !strings.Contains(s, "") {
+ t.Fatalf("expected backlink in directory listing")
+ }
+ if !strings.Contains(s, "") {
+ t.Fatalf("expected file in directory listing")
+ }
+ if !strings.Contains(s, k3.Cid().String()) {
+ t.Fatalf("expected hash in directory listing")
+ }
+}
+
+func TestPretty404(t *testing.T) {
+ ts, api, root := newTestServerAndNode(t, nil)
+ t.Logf("test server url: %s", ts.URL)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ k, err := api.ResolvePath(ctx, ipath.Join(ipath.IpfsPath(root), t.Name()))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ host := "example.net"
+ api.namesys["/ipns/"+host] = path.FromString(k.String())
+
+ for _, test := range []struct {
+ path string
+ accept string
+ status int
+ text string
+ }{
+ {"/ipfs-404.html", "text/html", http.StatusOK, "Custom 404"},
+ {"/nope", "text/html", http.StatusNotFound, "Custom 404"},
+ {"/nope", "text/*", http.StatusNotFound, "Custom 404"},
+ {"/nope", "*/*", http.StatusNotFound, "Custom 404"},
+ {"/nope", "application/json", http.StatusNotFound, fmt.Sprintf("ipfs resolve -r /ipns/example.net/nope: no link named \"nope\" under %s\n", k.Cid().String())},
+ {"/deeper/nope", "text/html", http.StatusNotFound, "Deep custom 404"},
+ {"/deeper/", "text/html", http.StatusOK, ""},
+ {"/deeper", "text/html", http.StatusOK, ""},
+ {"/nope/nope", "text/html", http.StatusNotFound, "Custom 404"},
+ } {
+ var c http.Client
+ req, err := http.NewRequest("GET", ts.URL+test.path, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Header.Add("Accept", test.accept)
+ req.Host = host
+ resp, err := c.Do(req)
+
+ if err != nil {
+ t.Fatalf("error requesting %s: %s", test.path, err)
+ }
+
+ defer resp.Body.Close()
+ if resp.StatusCode != test.status {
+ t.Fatalf("got %d, expected %d, from %s", resp.StatusCode, test.status, test.path)
+ }
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf("error reading response from %s: %s", test.path, err)
+ }
+
+ if test.text != "" && string(body) != test.text {
+ t.Fatalf("unexpected response body from %s: got %q, expected %q", test.path, body, test.text)
+ }
+ }
+}
+
+func TestCacheControlImmutable(t *testing.T) {
+ ts, _, root := newTestServerAndNode(t, nil)
+ t.Logf("test server url: %s", ts.URL)
+
+ req, err := http.NewRequest(http.MethodGet, ts.URL+"/ipfs/"+root.String()+"/", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ res, err := doWithoutRedirect(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // check the immutable tag isn't set
+ hdrs, ok := res.Header["Cache-Control"]
+ if ok {
+ for _, hdr := range hdrs {
+ if strings.Contains(hdr, "immutable") {
+ t.Fatalf("unexpected Cache-Control: immutable on directory listing: %s", hdr)
+ }
+ }
+ }
+}
+
+func TestGoGetSupport(t *testing.T) {
+ ts, _, root := newTestServerAndNode(t, nil)
+ t.Logf("test server url: %s", ts.URL)
+
+ // mimic go-get
+ req, err := http.NewRequest(http.MethodGet, ts.URL+"/ipfs/"+root.String()+"?go-get=1", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ res, err := doWithoutRedirect(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if res.StatusCode != 200 {
+ t.Errorf("status is %d, expected 200", res.StatusCode)
+ }
}
diff --git a/gateway/hostname_test.go b/gateway/hostname_test.go
index f4ce73241..96905f271 100644
--- a/gateway/hostname_test.go
+++ b/gateway/hostname_test.go
@@ -11,14 +11,14 @@ import (
)
func TestToSubdomainURL(t *testing.T) {
- gwAPI := newMockApi()
+ gwAPI, _ := newMockAPI(t)
testCID, err := cid.Decode("bafkqaglimvwgy3zakrsxg5cun5jxkyten5wwc2lokvjeycq")
if err != nil {
t.Fatal(err)
}
- gwAPI.ns["/ipns/dnslink.long-name.example.com"] = path.FromString(testCID.String())
- gwAPI.ns["/ipns/dnslink.too-long.f1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5o.example.com"] = path.FromString(testCID.String())
+ gwAPI.namesys["/ipns/dnslink.long-name.example.com"] = path.FromString(testCID.String())
+ gwAPI.namesys["/ipns/dnslink.too-long.f1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5o.example.com"] = path.FromString(testCID.String())
httpRequest := httptest.NewRequest("GET", "http://127.0.0.1:8080", nil)
httpsRequest := httptest.NewRequest("GET", "https://https-request-stub.example.com", nil)
httpsProxiedRequest := httptest.NewRequest("GET", "http://proxied-https-request-stub.example.com", nil)
diff --git a/gateway/testdata/fixtures.car b/gateway/testdata/fixtures.car
new file mode 100644
index 000000000..e01ca5c31
Binary files /dev/null and b/gateway/testdata/fixtures.car differ
diff --git a/go.mod b/go.mod
index f7300ef46..ade83a31a 100644
--- a/go.mod
+++ b/go.mod
@@ -12,13 +12,16 @@ require (
github.com/gogo/protobuf v1.3.2
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
+ github.com/ipfs/go-blockservice v0.5.0
github.com/ipfs/go-cid v0.3.2
github.com/ipfs/go-datastore v0.6.0
github.com/ipfs/go-detect-race v0.0.1
+ github.com/ipfs/go-fetcher v1.6.1
github.com/ipfs/go-ipfs-blockstore v1.2.0
github.com/ipfs/go-ipfs-blocksutil v0.0.1
github.com/ipfs/go-ipfs-delay v0.0.1
github.com/ipfs/go-ipfs-exchange-interface v0.2.0
+ github.com/ipfs/go-ipfs-exchange-offline v0.3.0
github.com/ipfs/go-ipfs-redirects-file v0.1.1
github.com/ipfs/go-ipfs-routing v0.3.0
github.com/ipfs/go-ipfs-util v0.0.2
@@ -26,12 +29,17 @@ require (
github.com/ipfs/go-ipns v0.3.0
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
github.com/ipfs/go-metrics-interface v0.0.1
github.com/ipfs/go-namesys v0.7.0
github.com/ipfs/go-path v0.3.0
github.com/ipfs/go-peertaskqueue v0.8.0
+ github.com/ipfs/go-unixfs v0.3.1
+ github.com/ipfs/go-unixfsnode v1.5.1
github.com/ipfs/interface-go-ipfs-core v0.10.0
github.com/ipld/go-car v0.5.0
+ github.com/ipld/go-car/v2 v2.5.1
+ github.com/ipld/go-codec-dagpb v1.5.0
github.com/ipld/go-ipld-prime v0.19.0
github.com/jbenet/goprocess v0.1.4
github.com/libp2p/go-buffer-pool v0.1.0
@@ -51,12 +59,13 @@ require (
go.opencensus.io v0.24.0
go.opentelemetry.io/otel v1.7.0
go.opentelemetry.io/otel/trace v1.7.0
- go.uber.org/multierr v1.8.0
+ go.uber.org/multierr v1.9.0
go.uber.org/zap v1.24.0
- golang.org/x/sys v0.3.0
+ golang.org/x/sys v0.4.0
)
require (
+ github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -70,18 +79,16 @@ require (
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/huin/goupnp v1.0.3 // indirect
github.com/ipfs/bbloom v0.0.4 // indirect
+ github.com/ipfs/go-bitfield v1.0.0 // indirect
github.com/ipfs/go-block-format v0.1.1 // indirect
- github.com/ipfs/go-blockservice v0.5.0 // indirect
- github.com/ipfs/go-fetcher v1.6.1 // indirect
github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect
+ github.com/ipfs/go-ipfs-files v0.3.0 // indirect
github.com/ipfs/go-ipfs-pq v0.0.2 // indirect
github.com/ipfs/go-ipld-cbor v0.0.6 // indirect
github.com/ipfs/go-ipld-legacy v0.1.1 // indirect
- github.com/ipfs/go-merkledag v0.9.0 // indirect
github.com/ipfs/go-verifcid v0.0.2 // indirect
- github.com/ipld/go-codec-dagpb v1.5.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
- github.com/klauspost/cpuid/v2 v2.2.1 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.3 // indirect
github.com/koron/go-ssdp v0.0.3 // indirect
github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
@@ -99,9 +106,10 @@ require (
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
+ github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
+ github.com/polydawn/refmt v0.89.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
@@ -109,13 +117,14 @@ require (
github.com/stretchr/objx v0.5.0 // indirect
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
- github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0 // indirect
+ github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect
+ github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa // indirect
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
go.uber.org/atomic v1.10.0 // indirect
- golang.org/x/crypto v0.4.0 // indirect
- golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
+ golang.org/x/crypto v0.5.0 // indirect
+ golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2 // indirect
golang.org/x/mod v0.7.0 // indirect
- golang.org/x/net v0.4.0 // indirect
+ golang.org/x/net v0.5.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/tools v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
diff --git a/go.sum b/go.sum
index 80fbf49d7..9def56b73 100644
--- a/go.sum
+++ b/go.sum
@@ -48,7 +48,6 @@ github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
-github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo=
github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
@@ -58,6 +57,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a h1:E/8AP5dFtMhl5KPJz66Kt9G0n+7Sn41Fy1wv9/jHOrc=
+github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@@ -202,6 +203,7 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
+github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -345,6 +347,8 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod
github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI=
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/go-bitfield v1.0.0 h1:y/XHm2GEmD9wKngheWNNCNL0pzrWXZwCdQGv1ikXknQ=
+github.com/ipfs/go-bitfield v1.0.0/go.mod h1:N/UiujQy+K+ceU1EF5EkVd1TNqevLrCQMIcAEPrdtus=
github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0=
github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs=
github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo=
@@ -398,6 +402,7 @@ github.com/ipfs/go-ipfs-blockstore v1.2.0 h1:n3WTeJ4LdICWs/0VSfjHrlqpPpl6MZ+ySd3
github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE=
github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ=
github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk=
+github.com/ipfs/go-ipfs-chunker v0.0.1 h1:cHUUxKFQ99pozdahi+uSC/3Y6HeRpi9oTeUHbE27SEw=
github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=
@@ -413,7 +418,11 @@ github.com/ipfs/go-ipfs-exchange-interface v0.2.0/go.mod h1:z6+RhJuDQbqKguVyslSO
github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0=
github.com/ipfs/go-ipfs-exchange-offline v0.1.1/go.mod h1:vTiBRIbzSwDD0OWm+i3xeT0mO7jG2cbJYatp3HPk5XY=
github.com/ipfs/go-ipfs-exchange-offline v0.3.0 h1:c/Dg8GDPzixGd0MC8Jh6mjOwU57uYokgWRFidfvEkuA=
+github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB02e++Z7521fMxqCNRrz9s=
github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=
+github.com/ipfs/go-ipfs-files v0.3.0 h1:fallckyc5PYjuMEitPNrjRfpwl7YFt69heCOUhsbGxQ=
+github.com/ipfs/go-ipfs-files v0.3.0/go.mod h1:xAUtYMwB+iu/dtf6+muHNSFQCJG2dSiStR2P6sn9tIM=
+github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs=
github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A=
github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY=
@@ -473,8 +482,11 @@ github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68
github.com/ipfs/go-peertaskqueue v0.8.0 h1:JyNO144tfu9bx6Hpo119zvbEL9iQ760FHOiJYsUjqaU=
github.com/ipfs/go-peertaskqueue v0.8.0/go.mod h1:cz8hEnnARq4Du5TGqiWKgMr/BOSQ5XOgMOh1K5YYKKM=
github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw=
-github.com/ipfs/go-unixfsnode v1.1.2 h1:aTsCdhwU0F4dMShMwYGroAj4v4EzSONLdoENebvTRb0=
+github.com/ipfs/go-unixfs v0.3.1 h1:LrfED0OGfG98ZEegO4/xiprx2O+yS+krCMQSp7zLVv8=
+github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o=
github.com/ipfs/go-unixfsnode v1.1.2/go.mod h1:5dcE2x03pyjHk4JjamXmunTMzz+VUtqvPwZjIEkfV6s=
+github.com/ipfs/go-unixfsnode v1.5.1 h1:JcR3t5C2nM1V7PMzhJ/Qmo19NkoFIKweDSZyDx+CjkI=
+github.com/ipfs/go-unixfsnode v1.5.1/go.mod h1:ed79DaG9IEuZITJVQn4U6MZDftv6I3ygUBLPfhEbHvk=
github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0=
github.com/ipfs/go-verifcid v0.0.2 h1:XPnUv0XmdH+ZIhLGKg6U2vaPaRDXb9urMyNVCE7uvTs=
github.com/ipfs/go-verifcid v0.0.2/go.mod h1:40cD9x1y4OWnFXbLNJYRe7MpNvWlMn3LZAG5Wb4xnPU=
@@ -482,6 +494,8 @@ github.com/ipfs/interface-go-ipfs-core v0.10.0 h1:b/psL1oqJcySdQAsIBfW5ZJJkOAsYl
github.com/ipfs/interface-go-ipfs-core v0.10.0/go.mod h1:F3EcmDy53GFkF0H3iEJpfJC320fZ/4G60eftnItrrJ0=
github.com/ipld/go-car v0.5.0 h1:kcCEa3CvYMs0iE5BzD5sV7O2EwMiCIp3uF8tA6APQT8=
github.com/ipld/go-car v0.5.0/go.mod h1:ppiN5GWpjOZU9PgpAZ9HbZd9ZgSpwPMr48fGRJOWmvE=
+github.com/ipld/go-car/v2 v2.5.1 h1:U2ux9JS23upEgrJScW8VQuxmE94560kYxj9CQUpcfmk=
+github.com/ipld/go-car/v2 v2.5.1/go.mod h1:jKjGOqoCj5zn6KjnabD6JbnCsMntqU2hLiU6baZVO3E=
github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA=
github.com/ipld/go-codec-dagpb v1.5.0 h1:RspDRdsJpLfgCI0ONhTAnbHdySGD4t+LHSPK4X1+R0k=
github.com/ipld/go-codec-dagpb v1.5.0/go.mod h1:0yRIutEFD8o1DGVqw4RSHh+BUTlJA9XWldxaaWR/o4g=
@@ -489,6 +503,7 @@ github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db/go.mod h1:KvB
github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8=
github.com/ipld/go-ipld-prime v0.19.0 h1:5axC7rJmPc17Emw6TelxGwnzALk0PdupZ2oj2roDj04=
github.com/ipld/go-ipld-prime v0.19.0/go.mod h1:Q9j3BaVXwaA3o5JUDNvptDDr/x8+F7FG6XJ8WI3ILg4=
+github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73 h1:TsyATB2ZRRQGTwafJdgEUQkmjOExRV0DNokcihZxbnQ=
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
@@ -531,8 +546,8 @@ github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6
github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.1 h1:U33DW0aiEj633gHYw3LoDNfkDiYnE5Q8M/TKJn2f2jI=
-github.com/klauspost/cpuid/v2 v2.2.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
+github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
@@ -919,6 +934,8 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2D
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk=
+github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -931,8 +948,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
-github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls=
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
+github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4=
+github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -1019,12 +1037,14 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
+github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
+github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
@@ -1072,18 +1092,23 @@ github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRW
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/warpfork/go-testmark v0.10.0 h1:E86YlUMYfwIacEsQGlnTvjk1IgYkyTGjPhF0RnwTCmw=
github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
-github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w=
github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
+github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
+github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4=
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM=
+github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0=
+github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ=
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=
-github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0 h1:obKzQ1ey5AJg5NKjgtTo/CKwLImVP4ETLRcsmzFJ4Qw=
-github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
+github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa h1:EyA027ZAkuaCLoxVX4r1TZMPy1d31fM6hbfQ4OU4I5o=
+github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
+github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E=
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
@@ -1136,8 +1161,8 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
-go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
+go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
+go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
@@ -1176,8 +1201,8 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
-golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
-golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
+golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
+golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1188,8 +1213,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
-golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2 h1:5sPMf9HJXrvBWIamTw+rTST0bZ3Mho2n1p58M0+W99c=
+golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1270,8 +1295,8 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
-golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
+golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1372,8 +1397,8 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
-golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
+golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1384,7 +1409,7 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
+golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=