diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e3090696f02..fd7ba120d83 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -54,7 +54,7 @@ jobs: shell: bash strategy: matrix: - repo-to-test-against: ["helia", "helia-ipns", "helia-unixfs"] # this needs to be manually kept in sync as new helia tests are written + repo-to-test-against: ["helia", "helia-ipns", "helia-unixfs", "helia-car", "helia-dag-json", "helia-dag-cbor", "helia-json", "helia-mfs"] # this needs to be manually kept in sync as new helia tests are written steps: - uses: actions/setup-node@v3 with: @@ -94,43 +94,6 @@ jobs: working-directory: interop/packages/interop env: KUBO_BINARY: ${{ github.workspace }}/cmd/ipfs/ipfs - go-ipfs-api: - needs: [interop-prep] - runs-on: ubuntu-latest - timeout-minutes: 5 - env: - TEST_DOCKER: 0 - TEST_FUSE: 0 - TEST_VERBOSE: 1 - TRAVIS: 1 - GIT_PAGER: cat - IPFS_CHECK_RCMGR_DEFAULTS: 1 - defaults: - run: - shell: bash - steps: - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - - uses: actions/download-artifact@v3 - with: - name: kubo - path: cmd/ipfs - - run: chmod +x cmd/ipfs/ipfs - - uses: actions/checkout@v4 - with: - repository: ipfs/go-ipfs-api - path: go-ipfs-api - - run: cmd/ipfs/ipfs daemon --init --enable-namesys-pubsub & - - run: | - while ! cmd/ipfs/ipfs id --api=/ip4/127.0.0.1/tcp/5001 2>/dev/null; do - sleep 1 - done - timeout-minutes: 5 - - run: go test -count=1 -v ./... - working-directory: go-ipfs-api - - run: cmd/ipfs/ipfs shutdown - if: always() ipfs-webui: needs: [interop-prep] runs-on: ${{ fromJSON(github.repository == 'ipfs/kubo' && '["self-hosted", "linux", "x64", "2xlarge"]' || '"ubuntu-latest"') }} diff --git a/CHANGELOG.md b/CHANGELOG.md index f15248cc119..0f75314a9b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Kubo Changelogs +- [v0.24](docs/changelogs/v0.24.md) - [v0.23](docs/changelogs/v0.23.md) - [v0.22](docs/changelogs/v0.22.md) - [v0.21](docs/changelogs/v0.21.md) diff --git a/README.md b/README.md index 066f0790ae0..74b53c3ad6e 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Featureset - [HTTP Kubo RPC API](https://docs.ipfs.tech/reference/kubo/rpc/) (`/api/v0`) to access and control the daemon - [Command Line Interface](https://docs.ipfs.tech/reference/kubo/cli/) based on (`/api/v0`) RPC API - [WebUI](https://github.com/ipfs/ipfs-webui/#readme) to manage the Kubo node +- [Content blocking](/docs/content-blocking.md) support for operators of public nodes ### Other implementations @@ -88,7 +89,6 @@ Before opening an issue, consider using one of the following locations to ensure - [Install Go](#install-go) - [Download and Compile IPFS](#download-and-compile-ipfs) - [Cross Compiling](#cross-compiling) - - [OpenSSL](#openssl) - [Troubleshooting](#troubleshooting) - [Getting Started](#getting-started) - [Usage](#usage) @@ -327,15 +327,6 @@ Compiling for a different platform is as simple as running: make build GOOS=myTargetOS GOARCH=myTargetArchitecture ``` -##### OpenSSL - -To build go-ipfs with OpenSSL support, append `GOTAGS=openssl` to your `make` invocation. Building with OpenSSL should significantly reduce the background CPU usage on nodes that frequently make or receive new connections. - -Note: OpenSSL requires CGO support and, by default, CGO is disabled when cross-compiling. To cross-compile with OpenSSL support, you must: - -1. Install a compiler toolchain for the target platform. -2. Set the `CGO_ENABLED=1` environment variable. - #### Troubleshooting - Separate [instructions are available for building on Windows](docs/windows.md). diff --git a/assets/assets.go b/assets/assets.go index 9dff80e074e..bb320b4fd7a 100644 --- a/assets/assets.go +++ b/assets/assets.go @@ -9,8 +9,8 @@ import ( "github.com/ipfs/kubo/core/coreapi" options "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" + "github.com/ipfs/boxo/path" cid "github.com/ipfs/go-cid" ) @@ -44,7 +44,7 @@ func addAssetList(nd *core.IpfsNode, l []string) (cid.Cid, error) { return cid.Cid{}, err } - basePath := path.IpfsPath(dirb.Cid()) + basePath := path.FromCid(dirb.Cid()) for _, p := range l { d, err := Asset.ReadFile(p) @@ -69,5 +69,5 @@ func addAssetList(nd *core.IpfsNode, l []string) (cid.Cid, error) { return cid.Cid{}, err } - return basePath.Cid(), nil + return basePath.RootCid(), nil } diff --git a/client/rpc/api_test.go b/client/rpc/api_test.go index 51f8cf89d8e..e2838cb16c6 100644 --- a/client/rpc/api_test.go +++ b/client/rpc/api_test.go @@ -12,8 +12,8 @@ import ( "time" iface "github.com/ipfs/boxo/coreiface" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/coreiface/tests" + "github.com/ipfs/boxo/path" "github.com/ipfs/kubo/test/cli/harness" ma "github.com/multiformats/go-multiaddr" "go.uber.org/multierr" @@ -70,7 +70,11 @@ func (np NodeProvider) MakeAPISwarm(t *testing.T, ctx context.Context, fullIdent apis[i] = api // empty node is pinned even with --empty-repo, we don't want that - emptyNode := path.New("/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn") + emptyNode, err := path.NewPath("/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn") + if err != nil { + return err + } + if err := api.Pin().Rm(ctx, emptyNode); err != nil { return err } @@ -126,7 +130,11 @@ func Test_NewURLApiWithClient_With_Headers(t *testing.T) { t.Fatal(err) } api.Headers.Set(headerToTest, expectedHeaderValue) - if err := api.Pin().Rm(context.Background(), path.New("/ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv")); err != nil { + p, err := path.NewPath("/ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv") + if err != nil { + t.Fatal(err) + } + if err := api.Pin().Rm(context.Background(), p); err != nil { t.Fatal(err) } } diff --git a/client/rpc/apifile.go b/client/rpc/apifile.go index 873a67b7be0..7a54995b181 100644 --- a/client/rpc/apifile.go +++ b/client/rpc/apifile.go @@ -6,9 +6,9 @@ import ( "fmt" "io" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" unixfs "github.com/ipfs/boxo/ipld/unixfs" + "github.com/ipfs/boxo/path" "github.com/ipfs/go-cid" ) @@ -17,7 +17,7 @@ const forwardSeekLimit = 1 << 14 // 16k func (api *UnixfsAPI) Get(ctx context.Context, p path.Path) (files.Node, error) { if p.Mutable() { // use resolved path in case we are dealing with IPNS / MFS var err error - p, err = api.core().ResolvePath(ctx, p) + p, _, err = api.core().ResolvePath(ctx, p) if err != nil { return nil, err } @@ -195,13 +195,13 @@ func (it *apiIter) Next() bool { switch it.cur.Type { case unixfs.THAMTShard, unixfs.TMetadata, unixfs.TDirectory: - it.curFile, err = it.core.getDir(it.ctx, path.IpfsPath(c), int64(it.cur.Size)) + it.curFile, err = it.core.getDir(it.ctx, path.FromCid(c), int64(it.cur.Size)) if err != nil { it.err = err return false } case unixfs.TFile: - it.curFile, err = it.core.getFile(it.ctx, path.IpfsPath(c), int64(it.cur.Size)) + it.curFile, err = it.core.getFile(it.ctx, path.FromCid(c), int64(it.cur.Size)) if err != nil { it.err = err return false diff --git a/client/rpc/block.go b/client/rpc/block.go index 2b0048380be..a5882a57e9d 100644 --- a/client/rpc/block.go +++ b/client/rpc/block.go @@ -8,7 +8,7 @@ import ( iface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" + "github.com/ipfs/boxo/path" "github.com/ipfs/go-cid" mc "github.com/multiformats/go-multicodec" mh "github.com/multiformats/go-multihash" @@ -27,8 +27,8 @@ func (s *blockStat) Size() int { return s.BSize } -func (s *blockStat) Path() path.Resolved { - return path.IpldPath(s.cid) +func (s *blockStat) Path() path.ImmutablePath { + return path.FromCid(s.cid) } func (api *BlockAPI) Put(ctx context.Context, r io.Reader, opts ...caopts.BlockPutOption) (iface.BlockStat, error) { diff --git a/client/rpc/dag.go b/client/rpc/dag.go index f4c9be351f2..098a959d8f1 100644 --- a/client/rpc/dag.go +++ b/client/rpc/dag.go @@ -7,8 +7,8 @@ import ( "io" "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" - "github.com/ipfs/go-block-format" + "github.com/ipfs/boxo/path" + blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" format "github.com/ipfs/go-ipld-format" multicodec "github.com/multiformats/go-multicodec" @@ -21,7 +21,7 @@ type ( ) func (api *HttpDagServ) Get(ctx context.Context, c cid.Cid) (format.Node, error) { - r, err := api.core().Block().Get(ctx, path.IpldPath(c)) + r, err := api.core().Block().Get(ctx, path.FromCid(c)) if err != nil { return nil, err } @@ -79,8 +79,8 @@ func (api *httpNodeAdder) add(ctx context.Context, nd format.Node, pin bool) err if err != nil { return err } - if !stat.Path().Cid().Equals(c) { - return fmt.Errorf("cids didn't match - local %s, remote %s", c.String(), stat.Path().Cid().String()) + if !stat.Path().RootCid().Equals(c) { + return fmt.Errorf("cids didn't match - local %s, remote %s", c.String(), stat.Path().RootCid().String()) } return nil } @@ -116,7 +116,7 @@ func (api *HttpDagServ) Pinning() format.NodeAdder { } func (api *HttpDagServ) Remove(ctx context.Context, c cid.Cid) error { - return api.core().Block().Rm(ctx, path.IpldPath(c)) // TODO: should we force rm? + return api.core().Block().Rm(ctx, path.FromCid(c)) // TODO: should we force rm? } func (api *HttpDagServ) RemoveMany(ctx context.Context, cids []cid.Cid) error { diff --git a/client/rpc/dht.go b/client/rpc/dht.go index ffdf3968193..852c189764c 100644 --- a/client/rpc/dht.go +++ b/client/rpc/dht.go @@ -5,7 +5,7 @@ import ( "encoding/json" caopts "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" + "github.com/ipfs/boxo/path" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/routing" ) @@ -42,12 +42,12 @@ func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopt return nil, err } - rp, err := api.core().ResolvePath(ctx, p) + rp, _, err := api.core().ResolvePath(ctx, p) if err != nil { return nil, err } - resp, err := api.core().Request("dht/findprovs", rp.Cid().String()). + resp, err := api.core().Request("dht/findprovs", rp.RootCid().String()). Option("num-providers", options.NumProviders). Send(ctx) if err != nil { @@ -98,12 +98,12 @@ func (api *DhtAPI) Provide(ctx context.Context, p path.Path, opts ...caopts.DhtP return err } - rp, err := api.core().ResolvePath(ctx, p) + rp, _, err := api.core().ResolvePath(ctx, p) if err != nil { return err } - return api.core().Request("dht/provide", rp.Cid().String()). + return api.core().Request("dht/provide", rp.RootCid().String()). Option("recursive", options.Recursive). Exec(ctx, nil) } diff --git a/client/rpc/key.go b/client/rpc/key.go index 487c14c3d1b..40027aa464e 100644 --- a/client/rpc/key.go +++ b/client/rpc/key.go @@ -6,31 +6,50 @@ import ( iface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" + "github.com/ipfs/boxo/ipns" + "github.com/ipfs/boxo/path" "github.com/libp2p/go-libp2p/core/peer" ) type KeyAPI HttpApi -type keyOutput struct { - JName string `json:"Name"` - Id string +type key struct { + name string + pid peer.ID + path path.Path +} + +func newKey(name, pidStr string) (*key, error) { + pid, err := peer.Decode(pidStr) + if err != nil { + return nil, err + } - pid peer.ID + path, err := path.NewPath("/ipns/" + ipns.NameFromPeer(pid).String()) + if err != nil { + return nil, err + } + + return &key{name: name, pid: pid, path: path}, nil } -func (k *keyOutput) Name() string { - return k.JName +func (k *key) Name() string { + return k.name } -func (k *keyOutput) Path() path.Path { - return path.New("/ipns/" + k.Id) +func (k *key) Path() path.Path { + return k.path } -func (k *keyOutput) ID() peer.ID { +func (k *key) ID() peer.ID { return k.pid } +type keyOutput struct { + Name string + Id string +} + func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.KeyGenerateOption) (iface.Key, error) { options, err := caopts.KeyGenerateOptions(opts...) if err != nil { @@ -45,8 +64,8 @@ func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.Key if err != nil { return nil, err } - out.pid, err = peer.Decode(out.Id) - return &out, err + + return newKey(out.Name, out.Id) } func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, opts ...caopts.KeyRenameOption) (iface.Key, bool, error) { @@ -68,25 +87,29 @@ func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, o return nil, false, err } - id := &keyOutput{JName: out.Now, Id: out.Id} - id.pid, err = peer.Decode(id.Id) - return id, out.Overwrite, err + key, err := newKey(out.Now, out.Id) + if err != nil { + return nil, false, err + } + + return key, out.Overwrite, err } func (api *KeyAPI) List(ctx context.Context) ([]iface.Key, error) { - var out struct{ Keys []*keyOutput } + var out struct { + Keys []keyOutput + } if err := api.core().Request("key/list").Exec(ctx, &out); err != nil { return nil, err } res := make([]iface.Key, len(out.Keys)) for i, k := range out.Keys { - var err error - k.pid, err = peer.Decode(k.Id) + key, err := newKey(k.Name, k.Id) if err != nil { return nil, err } - res[i] = k + res[i] = key } return res, nil @@ -98,14 +121,13 @@ func (api *KeyAPI) Self(ctx context.Context) (iface.Key, error) { return nil, err } - var err error - out := keyOutput{JName: "self", Id: id.ID} - out.pid, err = peer.Decode(out.Id) - return &out, err + return newKey("self", id.ID) } func (api *KeyAPI) Remove(ctx context.Context, name string) (iface.Key, error) { - var out struct{ Keys []keyOutput } + var out struct { + Keys []keyOutput + } if err := api.core().Request("key/rm", name).Exec(ctx, &out); err != nil { return nil, err } @@ -113,9 +135,7 @@ func (api *KeyAPI) Remove(ctx context.Context, name string) (iface.Key, error) { return nil, errors.New("got unexpected number of keys back") } - var err error - out.Keys[0].pid, err = peer.Decode(out.Keys[0].Id) - return &out.Keys[0], err + return newKey(out.Keys[0].Name, out.Keys[0].Id) } func (api *KeyAPI) core() *HttpApi { diff --git a/client/rpc/name.go b/client/rpc/name.go index 5ad9d16cb8a..eb01ee3cdf0 100644 --- a/client/rpc/name.go +++ b/client/rpc/name.go @@ -8,9 +8,9 @@ import ( iface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - nsopts "github.com/ipfs/boxo/coreiface/options/namesys" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/ipns" + "github.com/ipfs/boxo/namesys" + "github.com/ipfs/boxo/path" ) type NameAPI HttpApi @@ -49,9 +49,9 @@ func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.Name return nil, err } - ropts := nsopts.ProcessOpts(options.ResolveOpts) - if ropts.Depth != nsopts.DefaultDepthLimit && ropts.Depth != 1 { - return nil, fmt.Errorf("Name.Resolve: depth other than 1 or %d not supported", nsopts.DefaultDepthLimit) + ropts := namesys.ProcessResolveOptions(options.ResolveOpts) + if ropts.Depth != namesys.DefaultDepthLimit && ropts.Depth != 1 { + return nil, fmt.Errorf("Name.Resolve: depth other than 1 or %d not supported", namesys.DefaultDepthLimit) } req := api.core().Request("name/resolve", name). @@ -84,7 +84,11 @@ func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.Name } var ires iface.IpnsResult if err == nil { - ires.Path = path.New(out.Path) + p, err := path.NewPath(out.Path) + if err != nil { + return + } + ires.Path = p } select { @@ -106,9 +110,9 @@ func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.Nam return nil, err } - ropts := nsopts.ProcessOpts(options.ResolveOpts) - if ropts.Depth != nsopts.DefaultDepthLimit && ropts.Depth != 1 { - return nil, fmt.Errorf("Name.Resolve: depth other than 1 or %d not supported", nsopts.DefaultDepthLimit) + ropts := namesys.ProcessResolveOptions(options.ResolveOpts) + if ropts.Depth != namesys.DefaultDepthLimit && ropts.Depth != 1 { + return nil, fmt.Errorf("Name.Resolve: depth other than 1 or %d not supported", namesys.DefaultDepthLimit) } req := api.core().Request("name/resolve", name). @@ -122,7 +126,7 @@ func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.Nam return nil, err } - return path.New(out.Path), nil + return path.NewPath(out.Path) } func (api *NameAPI) core() *HttpApi { diff --git a/client/rpc/object.go b/client/rpc/object.go index 7464cea1a72..b8d09752fc5 100644 --- a/client/rpc/object.go +++ b/client/rpc/object.go @@ -8,9 +8,9 @@ import ( iface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/ipld/merkledag" ft "github.com/ipfs/boxo/ipld/unixfs" + "github.com/ipfs/boxo/path" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" ) @@ -40,10 +40,10 @@ func (api *ObjectAPI) New(ctx context.Context, opts ...caopts.ObjectNewOption) ( return n, nil } -func (api *ObjectAPI) Put(ctx context.Context, r io.Reader, opts ...caopts.ObjectPutOption) (path.Resolved, error) { +func (api *ObjectAPI) Put(ctx context.Context, r io.Reader, opts ...caopts.ObjectPutOption) (path.ImmutablePath, error) { options, err := caopts.ObjectPutOptions(opts...) if err != nil { - return nil, err + return path.ImmutablePath{}, err } var out objectOut @@ -54,15 +54,15 @@ func (api *ObjectAPI) Put(ctx context.Context, r io.Reader, opts ...caopts.Objec FileBody(r). Exec(ctx, &out) if err != nil { - return nil, err + return path.ImmutablePath{}, err } c, err := cid.Parse(out.Hash) if err != nil { - return nil, err + return path.ImmutablePath{}, err } - return path.IpfsPath(c), nil + return path.FromCid(c), nil } func (api *ObjectAPI) Get(ctx context.Context, p path.Path) (ipld.Node, error) { @@ -153,10 +153,10 @@ func (api *ObjectAPI) Stat(ctx context.Context, p path.Path) (*iface.ObjectStat, }, nil } -func (api *ObjectAPI) AddLink(ctx context.Context, base path.Path, name string, child path.Path, opts ...caopts.ObjectAddLinkOption) (path.Resolved, error) { +func (api *ObjectAPI) AddLink(ctx context.Context, base path.Path, name string, child path.Path, opts ...caopts.ObjectAddLinkOption) (path.ImmutablePath, error) { options, err := caopts.ObjectAddLinkOptions(opts...) if err != nil { - return nil, err + return path.ImmutablePath{}, err } var out objectOut @@ -164,65 +164,65 @@ func (api *ObjectAPI) AddLink(ctx context.Context, base path.Path, name string, Option("create", options.Create). Exec(ctx, &out) if err != nil { - return nil, err + return path.ImmutablePath{}, err } c, err := cid.Parse(out.Hash) if err != nil { - return nil, err + return path.ImmutablePath{}, err } - return path.IpfsPath(c), nil + return path.FromCid(c), nil } -func (api *ObjectAPI) RmLink(ctx context.Context, base path.Path, link string) (path.Resolved, error) { +func (api *ObjectAPI) RmLink(ctx context.Context, base path.Path, link string) (path.ImmutablePath, error) { var out objectOut err := api.core().Request("object/patch/rm-link", base.String(), link). Exec(ctx, &out) if err != nil { - return nil, err + return path.ImmutablePath{}, err } c, err := cid.Parse(out.Hash) if err != nil { - return nil, err + return path.ImmutablePath{}, err } - return path.IpfsPath(c), nil + return path.FromCid(c), nil } -func (api *ObjectAPI) AppendData(ctx context.Context, p path.Path, r io.Reader) (path.Resolved, error) { +func (api *ObjectAPI) AppendData(ctx context.Context, p path.Path, r io.Reader) (path.ImmutablePath, error) { var out objectOut err := api.core().Request("object/patch/append-data", p.String()). FileBody(r). Exec(ctx, &out) if err != nil { - return nil, err + return path.ImmutablePath{}, err } c, err := cid.Parse(out.Hash) if err != nil { - return nil, err + return path.ImmutablePath{}, err } - return path.IpfsPath(c), nil + return path.FromCid(c), nil } -func (api *ObjectAPI) SetData(ctx context.Context, p path.Path, r io.Reader) (path.Resolved, error) { +func (api *ObjectAPI) SetData(ctx context.Context, p path.Path, r io.Reader) (path.ImmutablePath, error) { var out objectOut err := api.core().Request("object/patch/set-data", p.String()). FileBody(r). Exec(ctx, &out) if err != nil { - return nil, err + return path.ImmutablePath{}, err } c, err := cid.Parse(out.Hash) if err != nil { - return nil, err + return path.ImmutablePath{}, err } - return path.IpfsPath(c), nil + return path.FromCid(c), nil } type change struct { @@ -246,10 +246,10 @@ func (api *ObjectAPI) Diff(ctx context.Context, a path.Path, b path.Path) ([]ifa Path: ch.Path, } if ch.Before != cid.Undef { - res[i].Before = path.IpfsPath(ch.Before) + res[i].Before = path.FromCid(ch.Before) } if ch.After != cid.Undef { - res[i].After = path.IpfsPath(ch.After) + res[i].After = path.FromCid(ch.After) } } return res, nil diff --git a/client/rpc/path.go b/client/rpc/path.go index 1b88eb07d26..03d3dfa559f 100644 --- a/client/rpc/path.go +++ b/client/rpc/path.go @@ -3,50 +3,46 @@ package rpc import ( "context" - "github.com/ipfs/boxo/coreiface/path" - ipfspath "github.com/ipfs/boxo/path" + "github.com/ipfs/boxo/path" cid "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" ) -func (api *HttpApi) ResolvePath(ctx context.Context, p path.Path) (path.Resolved, error) { +func (api *HttpApi) ResolvePath(ctx context.Context, p path.Path) (path.ImmutablePath, []string, error) { var out struct { Cid cid.Cid RemPath string } - // TODO: this is hacky, fixing https://github.com/ipfs/go-ipfs/issues/5703 would help - var err error - if p.Namespace() == "ipns" { + if p.Namespace() == path.IPNSNamespace { if p, err = api.Name().Resolve(ctx, p.String()); err != nil { - return nil, err + return path.ImmutablePath{}, nil, err } } if err := api.Request("dag/resolve", p.String()).Exec(ctx, &out); err != nil { - return nil, err + return path.ImmutablePath{}, nil, err } - // TODO: - ipath, err := ipfspath.FromSegments("/"+p.Namespace()+"/", out.Cid.String(), out.RemPath) + p, err = path.NewPathFromSegments(p.Namespace(), out.Cid.String(), out.RemPath) if err != nil { - return nil, err + return path.ImmutablePath{}, nil, err } - root, err := cid.Parse(ipfspath.Path(p.String()).Segments()[1]) + imPath, err := path.NewImmutablePath(p) if err != nil { - return nil, err + return path.ImmutablePath{}, nil, err } - return path.NewResolvedPath(ipath, out.Cid, root, out.RemPath), nil + return imPath, path.StringToSegments(out.RemPath), nil } func (api *HttpApi) ResolveNode(ctx context.Context, p path.Path) (ipld.Node, error) { - rp, err := api.ResolvePath(ctx, p) + rp, _, err := api.ResolvePath(ctx, p) if err != nil { return nil, err } - return api.Dag().Get(ctx, rp.Cid()) + return api.Dag().Get(ctx, rp.RootCid()) } diff --git a/client/rpc/pin.go b/client/rpc/pin.go index e8aecf11cf6..486e5115b5b 100644 --- a/client/rpc/pin.go +++ b/client/rpc/pin.go @@ -8,7 +8,7 @@ import ( iface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" + "github.com/ipfs/boxo/path" "github.com/ipfs/go-cid" "github.com/pkg/errors" ) @@ -24,7 +24,7 @@ type pinRefKeyList struct { } type pin struct { - path path.Resolved + path path.ImmutablePath typ string err error } @@ -33,7 +33,7 @@ func (p pin) Err() error { return p.err } -func (p pin) Path() path.Resolved { +func (p pin) Path() path.ImmutablePath { return p.path } @@ -102,7 +102,7 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan i } select { - case ch <- pin{typ: out.Type, path: path.IpldPath(c)}: + case ch <- pin{typ: out.Type, path: path.FromCid(c)}: case <-ctx.Done(): return } @@ -182,8 +182,8 @@ type badNode struct { cid cid.Cid } -func (n badNode) Path() path.Resolved { - return path.IpldPath(n.cid) +func (n badNode) Path() path.ImmutablePath { + return path.FromCid(n.cid) } func (n badNode) Err() error { diff --git a/client/rpc/unixfs.go b/client/rpc/unixfs.go index e19deec220c..be8ddb22d22 100644 --- a/client/rpc/unixfs.go +++ b/client/rpc/unixfs.go @@ -9,10 +9,10 @@ import ( iface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" unixfs "github.com/ipfs/boxo/ipld/unixfs" unixfs_pb "github.com/ipfs/boxo/ipld/unixfs/pb" + "github.com/ipfs/boxo/path" "github.com/ipfs/go-cid" mh "github.com/multiformats/go-multihash" ) @@ -26,15 +26,15 @@ type addEvent struct { type UnixfsAPI HttpApi -func (api *UnixfsAPI) Add(ctx context.Context, f files.Node, opts ...caopts.UnixfsAddOption) (path.Resolved, error) { +func (api *UnixfsAPI) Add(ctx context.Context, f files.Node, opts ...caopts.UnixfsAddOption) (path.ImmutablePath, error) { options, _, err := caopts.UnixfsAddOptions(opts...) if err != nil { - return nil, err + return path.ImmutablePath{}, err } mht, ok := mh.Codes[options.MhType] if !ok { - return nil, fmt.Errorf("unknowm mhType %d", options.MhType) + return path.ImmutablePath{}, fmt.Errorf("unknowm mhType %d", options.MhType) } req := api.core().Request("add"). @@ -65,7 +65,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, f files.Node, opts ...caopts.Unix version, err := api.core().loadRemoteVersion() if err != nil { - return nil, err + return path.ImmutablePath{}, err } useEncodedAbsPaths := version.LT(encodedAbsolutePathVersion) req.Body(files.NewMultiFileReader(d, false, useEncodedAbsPaths)) @@ -73,10 +73,10 @@ func (api *UnixfsAPI) Add(ctx context.Context, f files.Node, opts ...caopts.Unix var out addEvent resp, err := req.Send(ctx) if err != nil { - return nil, err + return path.ImmutablePath{}, err } if resp.Error != nil { - return nil, resp.Error + return path.ImmutablePath{}, resp.Error } defer resp.Output.Close() dec := json.NewDecoder(resp.Output) @@ -88,7 +88,7 @@ loop: case io.EOF: break loop default: - return nil, err + return path.ImmutablePath{}, err } out = evt @@ -102,26 +102,26 @@ loop: if out.Hash != "" { c, err := cid.Parse(out.Hash) if err != nil { - return nil, err + return path.ImmutablePath{}, err } - ifevt.Path = path.IpfsPath(c) + ifevt.Path = path.FromCid(c) } select { case options.Events <- ifevt: case <-ctx.Done(): - return nil, ctx.Err() + return path.ImmutablePath{}, ctx.Err() } } } c, err := cid.Parse(out.Hash) if err != nil { - return nil, err + return path.ImmutablePath{}, err } - return path.IpfsPath(c), nil + return path.FromCid(c), nil } type lsLink struct { diff --git a/cmd/ipfs/add_migrations.go b/cmd/ipfs/add_migrations.go index e0138112112..566158d0f7e 100644 --- a/cmd/ipfs/add_migrations.go +++ b/cmd/ipfs/add_migrations.go @@ -10,8 +10,8 @@ import ( coreiface "github.com/ipfs/boxo/coreiface" "github.com/ipfs/boxo/coreiface/options" - ipath "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" + "github.com/ipfs/boxo/path" "github.com/ipfs/kubo/core" "github.com/ipfs/kubo/core/coreapi" "github.com/ipfs/kubo/repo/fsrepo/migrations" @@ -98,7 +98,7 @@ func addMigrationFiles(ctx context.Context, node *core.IpfsNode, paths []string, // addMigrationPaths adds the files at paths to IPFS, optionally pinning // them. This is done after connecting to the peer. -func addMigrationPaths(ctx context.Context, node *core.IpfsNode, peerInfo peer.AddrInfo, paths []ipath.Path, pin bool) error { +func addMigrationPaths(ctx context.Context, node *core.IpfsNode, peerInfo peer.AddrInfo, paths []path.Path, pin bool) error { if len(paths) == 0 { return errors.New("nothing downloaded by ipfs fetcher") } @@ -142,7 +142,7 @@ func addMigrationPaths(ctx context.Context, node *core.IpfsNode, peerInfo peer.A return nil } -func ipfsGet(ctx context.Context, ufs coreiface.UnixfsAPI, ipfsPath ipath.Path) error { +func ipfsGet(ctx context.Context, ufs coreiface.UnixfsAPI, ipfsPath path.Path) error { nd, err := ufs.Get(ctx, ipfsPath) if err != nil { return err diff --git a/cmd/ipfs/init.go b/cmd/ipfs/init.go index 0c5223d7fce..6d03b12c906 100644 --- a/cmd/ipfs/init.go +++ b/cmd/ipfs/init.go @@ -11,7 +11,7 @@ import ( "strings" unixfs "github.com/ipfs/boxo/ipld/unixfs" - path "github.com/ipfs/boxo/path" + "github.com/ipfs/boxo/path" assets "github.com/ipfs/kubo/assets" oldcmds "github.com/ipfs/kubo/commands" core "github.com/ipfs/kubo/core" diff --git a/core/bootstrap/bootstrap.go b/core/bootstrap/bootstrap.go deleted file mode 100644 index 5cde5037193..00000000000 --- a/core/bootstrap/bootstrap.go +++ /dev/null @@ -1,371 +0,0 @@ -package bootstrap - -import ( - "context" - "errors" - "io" - "math/rand" - "sync" - "sync/atomic" - "time" - - logging "github.com/ipfs/go-log" - "github.com/jbenet/goprocess" - goprocessctx "github.com/jbenet/goprocess/context" - periodicproc "github.com/jbenet/goprocess/periodic" - "github.com/libp2p/go-libp2p/core/host" - "github.com/libp2p/go-libp2p/core/network" - "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/core/peerstore" - "github.com/libp2p/go-libp2p/core/routing" -) - -var log = logging.Logger("bootstrap") - -// ErrNotEnoughBootstrapPeers signals that we do not have enough bootstrap -// peers to bootstrap correctly. -var ErrNotEnoughBootstrapPeers = errors.New("not enough bootstrap peers to bootstrap") - -// BootstrapConfig specifies parameters used in an IpfsNode's network -// bootstrapping process. -type BootstrapConfig struct { - // MinPeerThreshold governs whether to bootstrap more connections. If the - // node has less open connections than this number, it will open connections - // to the bootstrap nodes. From there, the routing system should be able - // to use the connections to the bootstrap nodes to connect to even more - // peers. Routing systems like the IpfsDHT do so in their own Bootstrap - // process, which issues random queries to find more peers. - MinPeerThreshold int - - // Period governs the periodic interval at which the node will - // attempt to bootstrap. The bootstrap process is not very expensive, so - // this threshold can afford to be small (<=30s). - Period time.Duration - - // ConnectionTimeout determines how long to wait for a bootstrap - // connection attempt before cancelling it. - ConnectionTimeout time.Duration - - // BootstrapPeers is a function that returns a set of bootstrap peers - // for the bootstrap process to use. This makes it possible for clients - // to control the peers the process uses at any moment. - BootstrapPeers func() []peer.AddrInfo - - // BackupBootstrapInterval governs the periodic interval at which the node will - // attempt to save connected nodes to use as temporary bootstrap peers. - BackupBootstrapInterval time.Duration - - // MaxBackupBootstrapSize controls the maximum number of peers we're saving - // as backup bootstrap peers. - MaxBackupBootstrapSize int - - saveBackupBootstrapPeers func(context.Context, []peer.AddrInfo) - loadBackupBootstrapPeers func(context.Context) []peer.AddrInfo -} - -// DefaultBootstrapConfig specifies default sane parameters for bootstrapping. -var DefaultBootstrapConfig = BootstrapConfig{ - MinPeerThreshold: 4, - Period: 30 * time.Second, - ConnectionTimeout: (30 * time.Second) / 3, // Perod / 3 - BackupBootstrapInterval: 1 * time.Hour, - MaxBackupBootstrapSize: 20, -} - -// BootstrapConfigWithPeers creates a default BootstrapConfig configured with -// the specified peers, and optional functions to load and save backup peers. -func BootstrapConfigWithPeers(pis []peer.AddrInfo, options ...func(*BootstrapConfig)) BootstrapConfig { - cfg := DefaultBootstrapConfig - cfg.BootstrapPeers = func() []peer.AddrInfo { - return pis - } - for _, opt := range options { - opt(&cfg) - } - return cfg -} - -// WithBackupPeers configures functions to load and save backup bootstrap peers. -func WithBackupPeers(load func(context.Context) []peer.AddrInfo, save func(context.Context, []peer.AddrInfo)) func(*BootstrapConfig) { - if save == nil && load != nil || save != nil && load == nil { - panic("both load and save backup bootstrap peers functions must be defined") - } - return func(cfg *BootstrapConfig) { - cfg.loadBackupBootstrapPeers = load - cfg.saveBackupBootstrapPeers = save - } -} - -// BackupPeers returns the load and save backup peers functions. -func (cfg *BootstrapConfig) BackupPeers() (func(context.Context) []peer.AddrInfo, func(context.Context, []peer.AddrInfo)) { - return cfg.loadBackupBootstrapPeers, cfg.saveBackupBootstrapPeers -} - -// SetBackupPeers sets the load and save backup peers functions. -func (cfg *BootstrapConfig) SetBackupPeers(load func(context.Context) []peer.AddrInfo, save func(context.Context, []peer.AddrInfo)) { - opt := WithBackupPeers(load, save) - opt(cfg) -} - -// Bootstrap kicks off IpfsNode bootstrapping. This function will periodically -// check the number of open connections and -- if there are too few -- initiate -// connections to well-known bootstrap peers. It also kicks off subsystem -// bootstrapping (i.e. routing). -func Bootstrap(id peer.ID, host host.Host, rt routing.Routing, cfg BootstrapConfig) (io.Closer, error) { - // make a signal to wait for one bootstrap round to complete. - doneWithRound := make(chan struct{}) - - if len(cfg.BootstrapPeers()) == 0 { - // We *need* to bootstrap but we have no bootstrap peers - // configured *at all*, inform the user. - log.Warn("no bootstrap nodes configured: go-ipfs may have difficulty connecting to the network") - } - - // the periodic bootstrap function -- the connection supervisor - periodic := func(worker goprocess.Process) { - ctx := goprocessctx.OnClosingContext(worker) - - if err := bootstrapRound(ctx, host, cfg); err != nil { - log.Debugf("%s bootstrap error: %s", id, err) - } - - // Exit the first call (triggered independently by `proc.Go`, not `Tick`) - // only after being done with the *single* Routing.Bootstrap call. Following - // periodic calls (`Tick`) will not block on this. - <-doneWithRound - } - - // kick off the node's periodic bootstrapping - proc := periodicproc.Tick(cfg.Period, periodic) - proc.Go(periodic) // run one right now. - - // kick off Routing.Bootstrap - if rt != nil { - ctx := goprocessctx.OnClosingContext(proc) - if err := rt.Bootstrap(ctx); err != nil { - proc.Close() - return nil, err - } - } - - doneWithRound <- struct{}{} - close(doneWithRound) // it no longer blocks periodic - - // If loadBackupBootstrapPeers is not nil then saveBackupBootstrapPeers - // must also not be nil. - if cfg.loadBackupBootstrapPeers != nil { - startSavePeersAsTemporaryBootstrapProc(cfg, host, proc) - } - - return proc, nil -} - -// Aside of the main bootstrap process we also run a secondary one that saves -// connected peers as a backup measure if we can't connect to the official -// bootstrap ones. These peers will serve as *temporary* bootstrap nodes. -func startSavePeersAsTemporaryBootstrapProc(cfg BootstrapConfig, host host.Host, bootstrapProc goprocess.Process) { - savePeersFn := func(worker goprocess.Process) { - ctx := goprocessctx.OnClosingContext(worker) - - if err := saveConnectedPeersAsTemporaryBootstrap(ctx, host, cfg); err != nil { - log.Debugf("saveConnectedPeersAsTemporaryBootstrap error: %s", err) - } - } - savePeersProc := periodicproc.Tick(cfg.BackupBootstrapInterval, savePeersFn) - - // When the main bootstrap process ends also terminate the 'save connected - // peers' ones. Coupling the two seems the easiest way to handle this backup - // process without additional complexity. - go func() { - <-bootstrapProc.Closing() - savePeersProc.Close() - }() - - // Run the first round now (after the first bootstrap process has finished) - // as the SavePeersPeriod can be much longer than bootstrap. - savePeersProc.Go(savePeersFn) -} - -func saveConnectedPeersAsTemporaryBootstrap(ctx context.Context, host host.Host, cfg BootstrapConfig) error { - // Randomize the list of connected peers, we don't prioritize anyone. - connectedPeers := randomizeList(host.Network().Peers()) - - bootstrapPeers := cfg.BootstrapPeers() - backupPeers := make([]peer.AddrInfo, 0, cfg.MaxBackupBootstrapSize) - foundPeers := make(map[peer.ID]struct{}, cfg.MaxBackupBootstrapSize+len(bootstrapPeers)) - - // Don't record bootstrap peers - for _, b := range bootstrapPeers { - foundPeers[b.ID] = struct{}{} - } - - // Choose peers to save and filter out the ones that are already bootstrap nodes. - for _, p := range connectedPeers { - if _, found := foundPeers[p]; found { - continue - } - foundPeers[p] = struct{}{} - - backupPeers = append(backupPeers, peer.AddrInfo{ - ID: p, - Addrs: host.Network().Peerstore().Addrs(p), - }) - - if len(backupPeers) >= cfg.MaxBackupBootstrapSize { - break - } - } - - // If we didn't reach the target number use previously stored connected peers. - if len(backupPeers) < cfg.MaxBackupBootstrapSize { - oldSavedPeers := cfg.loadBackupBootstrapPeers(ctx) - log.Debugf("missing %d peers to reach backup bootstrap target of %d, trying from previous list of %d saved peers", - cfg.MaxBackupBootstrapSize-len(backupPeers), cfg.MaxBackupBootstrapSize, len(oldSavedPeers)) - - // Add some of the old saved peers. Ensure we don't duplicate them. - for _, p := range oldSavedPeers { - if _, found := foundPeers[p.ID]; found { - continue - } - foundPeers[p.ID] = struct{}{} - - backupPeers = append(backupPeers, p) - - if len(backupPeers) >= cfg.MaxBackupBootstrapSize { - break - } - } - } - - cfg.saveBackupBootstrapPeers(ctx, backupPeers) - log.Debugf("saved %d peers (of %d target) as bootstrap backup in the config", len(backupPeers), cfg.MaxBackupBootstrapSize) - return nil -} - -// Connect to as many peers needed to reach the BootstrapConfig.MinPeerThreshold. -// Peers can be original bootstrap or temporary ones (drawn from a list of -// persisted previously connected peers). -func bootstrapRound(ctx context.Context, host host.Host, cfg BootstrapConfig) error { - ctx, cancel := context.WithTimeout(ctx, cfg.ConnectionTimeout) - defer cancel() - id := host.ID() - - // get bootstrap peers from config. retrieving them here makes - // sure we remain observant of changes to client configuration. - peers := cfg.BootstrapPeers() - // determine how many bootstrap connections to open - connected := host.Network().Peers() - if len(connected) >= cfg.MinPeerThreshold { - log.Debugf("%s core bootstrap skipped -- connected to %d (> %d) nodes", - id, len(connected), cfg.MinPeerThreshold) - return nil - } - numToDial := cfg.MinPeerThreshold - len(connected) // numToDial > 0 - - if len(peers) > 0 { - numToDial -= int(peersConnect(ctx, host, peers, numToDial, true)) - if numToDial <= 0 { - return nil - } - } - - if cfg.loadBackupBootstrapPeers == nil { - log.Debugf("not enough bootstrap peers to fill the remaining target of %d connections", numToDial) - return ErrNotEnoughBootstrapPeers - } - - log.Debugf("not enough bootstrap peers to fill the remaining target of %d connections, trying backup list", numToDial) - - tempBootstrapPeers := cfg.loadBackupBootstrapPeers(ctx) - if len(tempBootstrapPeers) > 0 { - numToDial -= int(peersConnect(ctx, host, tempBootstrapPeers, numToDial, false)) - if numToDial <= 0 { - return nil - } - } - - log.Debugf("tried both original bootstrap peers and temporary ones but still missing target of %d connections", numToDial) - - return ErrNotEnoughBootstrapPeers -} - -// Attempt to make `needed` connections from the `availablePeers` list. Mark -// peers as either `permanent` or temporary when adding them to the Peerstore. -// Return the number of connections completed. We eagerly over-connect in parallel, -// so we might connect to more than needed. -// (We spawn as many routines and attempt connections as the number of availablePeers, -// but this list comes from restricted sets of original or temporary bootstrap -// nodes which will keep it under a sane value.) -func peersConnect(ctx context.Context, ph host.Host, availablePeers []peer.AddrInfo, needed int, permanent bool) uint64 { - peers := randomizeList(availablePeers) - - // Monitor the number of connections and stop if we reach the target. - var connected uint64 - ctx, cancel := context.WithCancel(ctx) - defer cancel() - go func() { - for { - select { - case <-ctx.Done(): - return - case <-time.After(1 * time.Second): - if int(atomic.LoadUint64(&connected)) >= needed { - cancel() - return - } - } - } - }() - - var wg sync.WaitGroup - for _, p := range peers { - - // performed asynchronously because when performed synchronously, if - // one `Connect` call hangs, subsequent calls are more likely to - // fail/abort due to an expiring context. - // Also, performed asynchronously for dial speed. - - if int(atomic.LoadUint64(&connected)) >= needed { - cancel() - break - } - - wg.Add(1) - go func(p peer.AddrInfo) { - defer wg.Done() - - // Skip addresses belonging to a peer we're already connected to. - // (Not a guarantee but a best-effort policy.) - if ph.Network().Connectedness(p.ID) == network.Connected { - return - } - log.Debugf("%s bootstrapping to %s", ph.ID(), p.ID) - - if err := ph.Connect(ctx, p); err != nil { - if ctx.Err() != context.Canceled { - log.Debugf("failed to bootstrap with %v: %s", p.ID, err) - } - return - } - if permanent { - // We're connecting to an original bootstrap peer, mark it as - // a permanent address (Connect will register it as TempAddrTTL). - ph.Peerstore().AddAddrs(p.ID, p.Addrs, peerstore.PermanentAddrTTL) - } - - log.Infof("bootstrapped with %v", p.ID) - atomic.AddUint64(&connected, 1) - }(p) - } - wg.Wait() - - return connected -} - -func randomizeList[T any](in []T) []T { - out := make([]T, len(in)) - for i, val := range rand.Perm(len(in)) { - out[i] = in[val] - } - return out -} diff --git a/core/bootstrap/bootstrap_test.go b/core/bootstrap/bootstrap_test.go deleted file mode 100644 index d933379d4e9..00000000000 --- a/core/bootstrap/bootstrap_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package bootstrap - -import ( - "context" - "crypto/rand" - "reflect" - "testing" - "time" - - "github.com/libp2p/go-libp2p" - "github.com/libp2p/go-libp2p/core/crypto" - "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/core/test" -) - -func TestRandomizeAddressList(t *testing.T) { - var ps []peer.AddrInfo - sizeofSlice := 10 - for i := 0; i < sizeofSlice; i++ { - pid, err := test.RandPeerID() - if err != nil { - t.Fatal(err) - } - - ps = append(ps, peer.AddrInfo{ID: pid}) - } - out := randomizeList(ps) - if len(out) != len(ps) { - t.Fail() - } -} - -func TestLoadAndSaveOptions(t *testing.T) { - loadFunc := func(_ context.Context) []peer.AddrInfo { return nil } - saveFunc := func(_ context.Context, _ []peer.AddrInfo) {} - - bootCfg := BootstrapConfigWithPeers(nil, WithBackupPeers(loadFunc, saveFunc)) - load, save := bootCfg.BackupPeers() - if load == nil { - t.Fatal("load function not assigned") - } - if reflect.ValueOf(load).Pointer() != reflect.ValueOf(loadFunc).Pointer() { - t.Fatal("load not assigned correct function") - } - if save == nil { - t.Fatal("save function not assigned") - } - if reflect.ValueOf(save).Pointer() != reflect.ValueOf(saveFunc).Pointer() { - t.Fatal("save not assigned correct function") - } - - assertPanics(t, "with only load func", func() { - BootstrapConfigWithPeers(nil, WithBackupPeers(loadFunc, nil)) - }) - - assertPanics(t, "with only save func", func() { - BootstrapConfigWithPeers(nil, WithBackupPeers(nil, saveFunc)) - }) - - bootCfg = BootstrapConfigWithPeers(nil, WithBackupPeers(nil, nil)) - load, save = bootCfg.BackupPeers() - if load != nil || save != nil { - t.Fatal("load and save functions should both be nil") - } -} - -func TestSetBackupPeers(t *testing.T) { - loadFunc := func(_ context.Context) []peer.AddrInfo { return nil } - saveFunc := func(_ context.Context, _ []peer.AddrInfo) {} - - bootCfg := DefaultBootstrapConfig - bootCfg.SetBackupPeers(loadFunc, saveFunc) - load, save := bootCfg.BackupPeers() - if load == nil { - t.Fatal("load function not assigned") - } - if reflect.ValueOf(load).Pointer() != reflect.ValueOf(loadFunc).Pointer() { - t.Fatal("load not assigned correct function") - } - if save == nil { - t.Fatal("save function not assigned") - } - if reflect.ValueOf(save).Pointer() != reflect.ValueOf(saveFunc).Pointer() { - t.Fatal("save not assigned correct function") - } - - assertPanics(t, "with only load func", func() { - bootCfg.SetBackupPeers(loadFunc, nil) - }) - - assertPanics(t, "with only save func", func() { - bootCfg.SetBackupPeers(nil, saveFunc) - }) - - bootCfg.SetBackupPeers(nil, nil) - load, save = bootCfg.BackupPeers() - if load != nil || save != nil { - t.Fatal("load and save functions should both be nil") - } -} - -func TestNoTempPeersLoadAndSave(t *testing.T) { - period := 500 * time.Millisecond - bootCfg := BootstrapConfigWithPeers(nil) - bootCfg.MinPeerThreshold = 2 - bootCfg.Period = period - - priv, pub, err := crypto.GenerateEd25519Key(rand.Reader) - if err != nil { - t.Fatal(err) - } - peerID, err := peer.IDFromPublicKey(pub) - if err != nil { - t.Fatal(err) - } - p2pHost, err := libp2p.New(libp2p.Identity(priv)) - if err != nil { - t.Fatal(err) - } - - bootstrapper, err := Bootstrap(peerID, p2pHost, nil, bootCfg) - if err != nil { - t.Fatal(err) - } - - time.Sleep(4 * period) - bootstrapper.Close() - -} - -func assertPanics(t *testing.T, name string, f func()) { - defer func() { - if r := recover(); r == nil { - t.Errorf("%s: did not panic as expected", name) - } - }() - - f() -} diff --git a/core/builder.go b/core/builder.go index 7a1d6fef227..4c54ddf8c5e 100644 --- a/core/builder.go +++ b/core/builder.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/ipfs/kubo/core/bootstrap" + "github.com/ipfs/boxo/bootstrap" "github.com/ipfs/kubo/core/node" "github.com/ipfs/go-metrics-interface" diff --git a/core/commands/add.go b/core/commands/add.go index fa78d70746b..bdde6cb4182 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -5,7 +5,7 @@ import ( "fmt" "io" "os" - "path" + gopath "path" "strings" "github.com/ipfs/kubo/core/commands/cmdenv" @@ -15,6 +15,7 @@ import ( "github.com/ipfs/boxo/coreiface/options" "github.com/ipfs/boxo/files" mfs "github.com/ipfs/boxo/mfs" + "github.com/ipfs/boxo/path" cmds "github.com/ipfs/go-ipfs-cmds" ipld "github.com/ipfs/go-ipld-format" mh "github.com/multiformats/go-multihash" @@ -301,7 +302,7 @@ See 'dag export' and 'dag import' for more information. return } // if MFS destination is a dir, append filename to the dir path - toFilesDst += path.Base(addit.Name()) + toFilesDst += gopath.Base(addit.Name()) } // error if we try to overwrite a preexisting file destination @@ -310,14 +311,14 @@ See 'dag export' and 'dag import' for more information. return } - _, err = mfs.Lookup(ipfsNode.FilesRoot, path.Dir(toFilesDst)) + _, err = mfs.Lookup(ipfsNode.FilesRoot, gopath.Dir(toFilesDst)) if err != nil { - errCh <- fmt.Errorf("%s: MFS destination parent %q %q does not exist: %w", toFilesOptionName, toFilesDst, path.Dir(toFilesDst), err) + errCh <- fmt.Errorf("%s: MFS destination parent %q %q does not exist: %w", toFilesOptionName, toFilesDst, gopath.Dir(toFilesDst), err) return } var nodeAdded ipld.Node - nodeAdded, err = api.Dag().Get(req.Context, pathAdded.Cid()) + nodeAdded, err = api.Dag().Get(req.Context, pathAdded.RootCid()) if err != nil { errCh <- err return @@ -339,14 +340,14 @@ See 'dag export' and 'dag import' for more information. } h := "" - if output.Path != nil { - h = enc.Encode(output.Path.Cid()) + if (output.Path != path.ImmutablePath{}) { + h = enc.Encode(output.Path.RootCid()) } if !dir && addit.Name() != "" { output.Name = addit.Name() } else { - output.Name = path.Join(addit.Name(), output.Name) + output.Name = gopath.Join(addit.Name(), output.Name) } if err := res.Emit(&AddEvent{ diff --git a/core/commands/block.go b/core/commands/block.go index 4ad19155407..103addcafaf 100644 --- a/core/commands/block.go +++ b/core/commands/block.go @@ -12,7 +12,7 @@ import ( "github.com/ipfs/kubo/core/commands/cmdutils" options "github.com/ipfs/boxo/coreiface/options" - path "github.com/ipfs/boxo/coreiface/path" + cmds "github.com/ipfs/go-ipfs-cmds" mh "github.com/multiformats/go-multihash" ) @@ -66,13 +66,18 @@ on raw IPFS blocks. It outputs the following to stdout: return err } - b, err := api.Block().Stat(req.Context, path.New(req.Arguments[0])) + p, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } + + b, err := api.Block().Stat(req.Context, p) if err != nil { return err } return cmds.EmitOnce(res, &BlockStat{ - Key: b.Path().Cid().String(), + Key: b.Path().RootCid().String(), Size: b.Size(), }) }, @@ -103,7 +108,12 @@ It takes a , and outputs the block to stdout. return err } - r, err := api.Block().Get(req.Context, path.New(req.Arguments[0])) + p, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } + + r, err := api.Block().Get(req.Context, p) if err != nil { return err } @@ -200,7 +210,7 @@ only for backward compatibility when a legacy CIDv0 is required (--format=v0). } err = res.Emit(&BlockStat{ - Key: p.Path().Cid().String(), + Key: p.Path().RootCid().String(), Size: p.Size(), }) if err != nil { @@ -255,7 +265,12 @@ It takes a list of CIDs to remove from the local datastore.. // TODO: use batching coreapi when done for _, b := range req.Arguments { - rp, err := api.ResolvePath(req.Context, path.New(b)) + p, err := cmdutils.PathOrCidPath(b) + if err != nil { + return err + } + + rp, _, err := api.ResolvePath(req.Context, p) if err != nil { return err } @@ -263,7 +278,7 @@ It takes a list of CIDs to remove from the local datastore.. err = api.Block().Rm(req.Context, rp, options.Block.Force(force)) if err != nil { if err := res.Emit(&removedBlock{ - Hash: rp.Cid().String(), + Hash: rp.RootCid().String(), Error: err.Error(), }); err != nil { return err @@ -273,7 +288,7 @@ It takes a list of CIDs to remove from the local datastore.. if !quiet { err := res.Emit(&removedBlock{ - Hash: rp.Cid().String(), + Hash: rp.RootCid().String(), }) if err != nil { return err diff --git a/core/commands/cat.go b/core/commands/cat.go index 92b045235c3..79e78cc772d 100644 --- a/core/commands/cat.go +++ b/core/commands/cat.go @@ -7,10 +7,10 @@ import ( "os" "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" "github.com/cheggaaa/pb" iface "github.com/ipfs/boxo/coreiface" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" cmds "github.com/ipfs/go-ipfs-cmds" ) @@ -127,8 +127,13 @@ func cat(ctx context.Context, api iface.CoreAPI, paths []string, offset int64, m if max == 0 { return nil, 0, nil } - for _, p := range paths { - f, err := api.Unixfs().Get(ctx, path.New(p)) + for _, pString := range paths { + p, err := cmdutils.PathOrCidPath(pString) + if err != nil { + return nil, 0, err + } + + f, err := api.Unixfs().Get(ctx, p) if err != nil { return nil, 0, err } diff --git a/core/commands/cmdutils/utils.go b/core/commands/cmdutils/utils.go index 954f476b6bf..87ddb9655ed 100644 --- a/core/commands/cmdutils/utils.go +++ b/core/commands/cmdutils/utils.go @@ -6,6 +6,7 @@ import ( cmds "github.com/ipfs/go-ipfs-cmds" coreiface "github.com/ipfs/boxo/coreiface" + "github.com/ipfs/boxo/path" "github.com/ipfs/go-cid" ) @@ -48,3 +49,19 @@ func CheckBlockSize(req *cmds.Request, size uint64) error { } return nil } + +// PathOrCidPath returns a path.Path built from the argument. It keeps the old +// behaviour by building a path from a CID string. +func PathOrCidPath(str string) (path.Path, error) { + p, err := path.NewPath(str) + if err == nil { + return p, nil + } + + if p, err := path.NewPath("/ipfs/" + str); err == nil { + return p, nil + } + + // Send back original err. + return nil, err +} diff --git a/core/commands/dag/dag.go b/core/commands/dag/dag.go index 07851eb316f..56aae4105da 100644 --- a/core/commands/dag/dag.go +++ b/core/commands/dag/dag.go @@ -5,11 +5,11 @@ import ( "encoding/json" "fmt" "io" + "path" "github.com/ipfs/kubo/core/commands/cmdenv" "github.com/ipfs/kubo/core/commands/cmdutils" - ipfspath "github.com/ipfs/boxo/path" cid "github.com/ipfs/go-cid" cidenc "github.com/ipfs/go-cidutil/cidenc" cmds "github.com/ipfs/go-ipfs-cmds" @@ -157,7 +157,7 @@ var DagResolveCmd = &cmds.Command{ } p := enc.Encode(out.Cid) if out.RemPath != "" { - p = ipfspath.Join([]string{p, out.RemPath}) + p = path.Join(p, out.RemPath) } fmt.Fprint(w, p) diff --git a/core/commands/dag/export.go b/core/commands/dag/export.go index d46fa6e21bf..d97718d200e 100644 --- a/core/commands/dag/export.go +++ b/core/commands/dag/export.go @@ -14,6 +14,7 @@ import ( cid "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" cmds "github.com/ipfs/go-ipfs-cmds" gocar "github.com/ipld/go-car" @@ -21,12 +22,10 @@ import ( ) func dagExport(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { - c, err := cid.Decode(req.Arguments[0]) + // Accept CID or a content path + p, err := cmdutils.PathOrCidPath(req.Arguments[0]) if err != nil { - return fmt.Errorf( - "unable to parse root specification (currently only bare CIDs are supported): %s", - err, - ) + return err } api, err := cmdenv.GetApi(env, req) @@ -34,6 +33,13 @@ func dagExport(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment return err } + // Resolve path and confirm the root block is available, fail fast if not + b, err := api.Block().Stat(req.Context, p) + if err != nil { + return err + } + c := b.Path().RootCid() + pipeR, pipeW := io.Pipe() errCh := make(chan error, 2) // we only report the 1st error diff --git a/core/commands/dag/get.go b/core/commands/dag/get.go index 1252293a8e4..d15d2b69ecb 100644 --- a/core/commands/dag/get.go +++ b/core/commands/dag/get.go @@ -4,9 +4,10 @@ import ( "fmt" "io" - "github.com/ipfs/boxo/coreiface/path" + "github.com/ipfs/boxo/path" ipldlegacy "github.com/ipfs/go-ipld-legacy" "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" "github.com/ipld/go-ipld-prime" "github.com/ipld/go-ipld-prime/multicodec" @@ -28,12 +29,17 @@ func dagGet(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) e return err } - rp, err := api.ResolvePath(req.Context, path.New(req.Arguments[0])) + p, err := cmdutils.PathOrCidPath(req.Arguments[0]) if err != nil { return err } - obj, err := api.Dag().Get(req.Context, rp.Cid()) + rp, remainder, err := api.ResolvePath(req.Context, p) + if err != nil { + return err + } + + obj, err := api.Dag().Get(req.Context, rp.RootCid()) if err != nil { return err } @@ -45,8 +51,8 @@ func dagGet(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) e finalNode := universal.(ipld.Node) - if len(rp.Remainder()) > 0 { - remainderPath := ipld.ParsePath(rp.Remainder()) + if len(remainder) > 0 { + remainderPath := ipld.ParsePath(path.SegmentsToString(remainder...)) finalNode, err = traversal.Get(finalNode, remainderPath) if err != nil { diff --git a/core/commands/dag/resolve.go b/core/commands/dag/resolve.go index 0f252be9db3..f8a4b36cd4b 100644 --- a/core/commands/dag/resolve.go +++ b/core/commands/dag/resolve.go @@ -1,8 +1,9 @@ package dagcmd import ( - "github.com/ipfs/boxo/coreiface/path" + "github.com/ipfs/boxo/path" "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" cmds "github.com/ipfs/go-ipfs-cmds" ) @@ -13,13 +14,18 @@ func dagResolve(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environmen return err } - rp, err := api.ResolvePath(req.Context, path.New(req.Arguments[0])) + p, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } + + rp, remainder, err := api.ResolvePath(req.Context, p) if err != nil { return err } return cmds.EmitOnce(res, &ResolveOutput{ - Cid: rp.Cid(), - RemPath: rp.Remainder(), + Cid: rp.RootCid(), + RemPath: path.SegmentsToString(remainder...), }) } diff --git a/core/commands/dag/stat.go b/core/commands/dag/stat.go index 23f4ab48167..bb9be7e0d90 100644 --- a/core/commands/dag/stat.go +++ b/core/commands/dag/stat.go @@ -5,12 +5,12 @@ import ( "io" "os" - "github.com/ipfs/boxo/coreiface/path" mdag "github.com/ipfs/boxo/ipld/merkledag" "github.com/ipfs/boxo/ipld/merkledag/traverse" cid "github.com/ipfs/go-cid" cmds "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" "github.com/ipfs/kubo/core/commands/e" ) @@ -29,19 +29,23 @@ func dagStat(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) cidSet := cid.NewSet() dagStatSummary := &DagStatSummary{DagStatsArray: []*DagStat{}} for _, a := range req.Arguments { - rp, err := api.ResolvePath(req.Context, path.New(a)) + p, err := cmdutils.PathOrCidPath(a) if err != nil { return err } - if len(rp.Remainder()) > 0 { + rp, remainder, err := api.ResolvePath(req.Context, p) + if err != nil { + return err + } + if len(remainder) > 0 { return fmt.Errorf("cannot return size for anything other than a DAG with a root CID") } - obj, err := nodeGetter.Get(req.Context, rp.Cid()) + obj, err := nodeGetter.Get(req.Context, rp.RootCid()) if err != nil { return err } - dagstats := &DagStat{Cid: rp.Cid()} + dagstats := &DagStat{Cid: rp.RootCid()} dagStatSummary.appendStats(dagstats) err = traverse.Traverse(obj, traverse.Options{ DAG: nodeGetter, diff --git a/core/commands/dht_test.go b/core/commands/dht_test.go index b0e03f5cdea..f0f7de703c9 100644 --- a/core/commands/dht_test.go +++ b/core/commands/dht_test.go @@ -11,7 +11,7 @@ import ( func TestKeyTranslation(t *testing.T) { pid := test.RandPeerIDFatal(t) - pkname := namesys.PkKeyForID(pid) + pkname := namesys.PkRoutingKey(pid) ipnsname := ipns.NameFromPeer(pid).RoutingKey() pkk, err := escapeDhtKey("/pk/" + pid.String()) diff --git a/core/commands/dns.go b/core/commands/dns.go index fda0cb6c333..5126a6cb153 100644 --- a/core/commands/dns.go +++ b/core/commands/dns.go @@ -4,8 +4,8 @@ import ( "fmt" "io" - nsopts "github.com/ipfs/boxo/coreiface/options/namesys" namesys "github.com/ipfs/boxo/namesys" + "github.com/ipfs/boxo/path" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" ncmd "github.com/ipfs/kubo/core/commands/name" @@ -47,20 +47,25 @@ It will work across multiple DNSLinks and IPNS keys. name := req.Arguments[0] resolver := namesys.NewDNSResolver(node.DNSResolver.LookupTXT) - var routing []nsopts.ResolveOpt + var routing []namesys.ResolveOption if !recursive { - routing = append(routing, nsopts.Depth(1)) + routing = append(routing, namesys.ResolveWithDepth(1)) } - output, err := resolver.Resolve(req.Context, name, routing...) + p, err := path.NewPath(name) + if err != nil { + return err + } + + val, err := resolver.Resolve(req.Context, p, routing...) if err != nil && (recursive || err != namesys.ErrResolveRecursion) { return err } - return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: output}) + return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: val.Path.String()}) }, Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *ncmd.ResolvedPath) error { - fmt.Fprintln(w, cmdenv.EscNonPrint(out.Path.String())) + fmt.Fprintln(w, cmdenv.EscNonPrint(out.Path)) return nil }), }, diff --git a/core/commands/files.go b/core/commands/files.go index ce1cf1cfc81..73ce9c8264f 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -16,11 +16,11 @@ import ( bservice "github.com/ipfs/boxo/blockservice" iface "github.com/ipfs/boxo/coreiface" - path "github.com/ipfs/boxo/coreiface/path" offline "github.com/ipfs/boxo/exchange/offline" dag "github.com/ipfs/boxo/ipld/merkledag" ft "github.com/ipfs/boxo/ipld/unixfs" mfs "github.com/ipfs/boxo/mfs" + "github.com/ipfs/boxo/path" cid "github.com/ipfs/go-cid" cidenc "github.com/ipfs/go-cidutil/cidenc" cmds "github.com/ipfs/go-ipfs-cmds" @@ -423,7 +423,12 @@ being GC'ed. func getNodeFromPath(ctx context.Context, node *core.IpfsNode, api iface.CoreAPI, p string) (ipld.Node, error) { switch { case strings.HasPrefix(p, "/ipfs/"): - return api.ResolveNode(ctx, path.New(p)) + pth, err := path.NewPath(p) + if err != nil { + return nil, err + } + + return api.ResolveNode(ctx, pth) default: fsn, err := mfs.Lookup(node.FilesRoot, p) if err != nil { diff --git a/core/commands/get.go b/core/commands/get.go index 35cd45c9de5..5b64c281bbd 100644 --- a/core/commands/get.go +++ b/core/commands/get.go @@ -12,10 +12,10 @@ import ( "strings" "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" "github.com/ipfs/kubo/core/commands/e" "github.com/cheggaaa/pb" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" "github.com/ipfs/boxo/tar" cmds "github.com/ipfs/go-ipfs-cmds" @@ -72,7 +72,10 @@ may also specify the level of compression by specifying '-l=<1-9>'. return err } - p := path.New(req.Arguments[0]) + p, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } file, err := api.Unixfs().Get(ctx, p) if err != nil { diff --git a/core/commands/ls.go b/core/commands/ls.go index 10d37856256..ee360796fb1 100644 --- a/core/commands/ls.go +++ b/core/commands/ls.go @@ -8,10 +8,10 @@ import ( "text/tabwriter" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" iface "github.com/ipfs/boxo/coreiface" options "github.com/ipfs/boxo/coreiface/options" - path "github.com/ipfs/boxo/coreiface/path" unixfs "github.com/ipfs/boxo/ipld/unixfs" unixfs_pb "github.com/ipfs/boxo/ipld/unixfs/pb" cmds "github.com/ipfs/go-ipfs-cmds" @@ -131,7 +131,12 @@ The JSON output contains type information. } for i, fpath := range paths { - results, err := api.Unixfs().Ls(req.Context, path.New(fpath), + pth, err := cmdutils.PathOrCidPath(fpath) + if err != nil { + return err + } + + results, err := api.Unixfs().Ls(req.Context, pth, options.Unixfs.ResolveChildren(resolveSize || resolveType)) if err != nil { return err diff --git a/core/commands/name/ipns.go b/core/commands/name/ipns.go index b5c7fd7e388..e03b9c66bc9 100644 --- a/core/commands/name/ipns.go +++ b/core/commands/name/ipns.go @@ -7,20 +7,18 @@ import ( "strings" "time" - namesys "github.com/ipfs/boxo/namesys" - cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" - options "github.com/ipfs/boxo/coreiface/options" - nsopts "github.com/ipfs/boxo/coreiface/options/namesys" - path "github.com/ipfs/boxo/path" + "github.com/ipfs/boxo/namesys" + "github.com/ipfs/boxo/path" cmds "github.com/ipfs/go-ipfs-cmds" logging "github.com/ipfs/go-log" + cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" ) var log = logging.Logger("core/commands/ipns") type ResolvedPath struct { - Path path.Path + Path string } const ( @@ -75,8 +73,8 @@ Resolve the value of a dnslink: Options: []cmds.Option{ cmds.BoolOption(recursiveOptionName, "r", "Resolve until the result is not an IPNS name.").WithDefault(true), cmds.BoolOption(nocacheOptionName, "n", "Do not use cached entries."), - cmds.UintOption(dhtRecordCountOptionName, "dhtrc", "Number of records to request for DHT resolution."), - cmds.StringOption(dhtTimeoutOptionName, "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."), + cmds.UintOption(dhtRecordCountOptionName, "dhtrc", "Number of records to request for DHT resolution.").WithDefault(uint(namesys.DefaultResolverDhtRecordCount)), + cmds.StringOption(dhtTimeoutOptionName, "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout.").WithDefault(namesys.DefaultResolverDhtTimeout.String()), cmds.BoolOption(streamOptionName, "s", "Stream entries as they are found."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { @@ -108,10 +106,10 @@ Resolve the value of a dnslink: } if !recursive { - opts = append(opts, options.Name.ResolveOption(nsopts.Depth(1))) + opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDepth(1))) } if rcok { - opts = append(opts, options.Name.ResolveOption(nsopts.DhtRecordCount(rc))) + opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDhtRecordCount(rc))) } if dhttok { d, err := time.ParseDuration(dhtt) @@ -121,7 +119,7 @@ Resolve the value of a dnslink: if d < 0 { return errors.New("DHT timeout value must be >= 0") } - opts = append(opts, options.Name.ResolveOption(nsopts.DhtTimeout(d))) + opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDhtTimeout(d))) } if !strings.HasPrefix(name, "/ipns/") { @@ -134,7 +132,12 @@ Resolve the value of a dnslink: return err } - return cmds.EmitOnce(res, &ResolvedPath{path.FromString(output.String())}) + pth, err := path.NewPath(output.String()) + if err != nil { + return err + } + + return cmds.EmitOnce(res, &ResolvedPath{pth.String()}) } output, err := api.Name().Search(req.Context, name, opts...) @@ -146,7 +149,7 @@ Resolve the value of a dnslink: if v.Err != nil && (recursive || v.Err != namesys.ErrResolveRecursion) { return v.Err } - if err := res.Emit(&ResolvedPath{path.FromString(v.Path.String())}); err != nil { + if err := res.Emit(&ResolvedPath{v.Path.String()}); err != nil { return err } diff --git a/core/commands/name/name.go b/core/commands/name/name.go index 3bcb5c8e415..37ab4df5352 100644 --- a/core/commands/name/name.go +++ b/core/commands/name/name.go @@ -10,7 +10,6 @@ import ( "github.com/ipfs/boxo/ipns" ipns_pb "github.com/ipfs/boxo/ipns/pb" - "github.com/ipfs/boxo/path" cmds "github.com/ipfs/go-ipfs-cmds" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" "google.golang.org/protobuf/proto" @@ -87,7 +86,7 @@ type IpnsInspectValidation struct { // IpnsInspectEntry contains the deserialized values from an IPNS Entry: // https://github.com/ipfs/specs/blob/main/ipns/IPNS.md#record-serialization-format type IpnsInspectEntry struct { - Value *path.Path + Value string ValidityType *ipns.ValidityType Validity *time.Time Sequence *uint64 @@ -157,7 +156,7 @@ Passing --verify will verify signature against provided public key. // Best effort to get the fields. Show everything we can. if v, err := rec.Value(); err == nil { - result.Entry.Value = &v + result.Entry.Value = v.String() } if v, err := rec.ValidityType(); err == nil { @@ -221,8 +220,8 @@ Passing --verify will verify signature against provided public key. tw := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0) defer tw.Flush() - if out.Entry.Value != nil { - fmt.Fprintf(tw, "Value:\t%q\n", out.Entry.Value.String()) + if out.Entry.Value != "" { + fmt.Fprintf(tw, "Value:\t%q\n", out.Entry.Value) } if out.Entry.ValidityType != nil { diff --git a/core/commands/name/publish.go b/core/commands/name/publish.go index 6cc51df14bd..6365470b670 100644 --- a/core/commands/name/publish.go +++ b/core/commands/name/publish.go @@ -7,10 +7,11 @@ import ( "time" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" iface "github.com/ipfs/boxo/coreiface" options "github.com/ipfs/boxo/coreiface/options" - path "github.com/ipfs/boxo/coreiface/path" + ipns "github.com/ipfs/boxo/ipns" cmds "github.com/ipfs/go-ipfs-cmds" ke "github.com/ipfs/kubo/core/commands/keyencode" ) @@ -59,7 +60,7 @@ Publish an with another name, added by an 'ipfs key' command: > ipfs name publish --key=mykey /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Published to QmSrPmbaUKA3ZodhzPWZnpFgcPMFWF4QsxXbkWfEptTBJd: /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy -Alternatively, publish an using a valid PeerID (as listed by +Alternatively, publish an using a valid PeerID (as listed by 'ipfs key list -l'): > ipfs name publish --key=QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy @@ -72,16 +73,13 @@ Alternatively, publish an using a valid PeerID (as listed by cmds.StringArg(ipfsPathOptionName, true, false, "ipfs path of the object to be published.").EnableStdin(), }, Options: []cmds.Option{ - cmds.BoolOption(resolveOptionName, "Check if the given path can be resolved before publishing.").WithDefault(true), - cmds.StringOption(lifeTimeOptionName, "t", - `Time duration that the record will be valid for. <> - This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are - "ns", "us" (or "µs"), "ms", "s", "m", "h".`).WithDefault("24h"), - cmds.BoolOption(allowOfflineOptionName, "When offline, save the IPNS record to the the local datastore without broadcasting to the network instead of simply failing."), - cmds.StringOption(ttlOptionName, "Time duration this record should be cached for. Uses the same syntax as the lifetime option. (caution: experimental)"), cmds.StringOption(keyOptionName, "k", "Name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'.").WithDefault("self"), - cmds.BoolOption(quieterOptionName, "Q", "Write only final hash."), + cmds.BoolOption(resolveOptionName, "Check if the given path can be resolved before publishing.").WithDefault(true), + cmds.StringOption(lifeTimeOptionName, "t", `Time duration the signed record will be valid for. Accepts durations such as "300s", "1.5h" or "7d2h45m"`).WithDefault(ipns.DefaultRecordLifetime.String()), + cmds.StringOption(ttlOptionName, "Time duration hint, akin to --lifetime, indicating how long to cache this record before checking for updates.").WithDefault(ipns.DefaultRecordTTL.String()), + cmds.BoolOption(quieterOptionName, "Q", "Write only final IPNS Name encoded as CIDv1 (for use in /ipns content paths)."), cmds.BoolOption(v1compatOptionName, "Produce a backward-compatible IPNS Record by including fields for both V1 and V2 signatures.").WithDefault(true), + cmds.BoolOption(allowOfflineOptionName, "When --offline, save the IPNS record to the the local datastore without broadcasting to the network (instead of failing)."), ke.OptionIPNSBase, }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { @@ -116,7 +114,10 @@ Alternatively, publish an using a valid PeerID (as listed by opts = append(opts, options.Name.TTL(d)) } - p := path.New(req.Arguments[0]) + p, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } if verifyExists, _ := req.Options[resolveOptionName].(bool); verifyExists { _, err := api.ResolveNode(req.Context, p) diff --git a/core/commands/object/diff.go b/core/commands/object/diff.go index fca026ac1c0..275f465d807 100644 --- a/core/commands/object/diff.go +++ b/core/commands/object/diff.go @@ -4,11 +4,12 @@ import ( "fmt" "io" - path "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/ipld/merkledag/dagutils" + "github.com/ipfs/boxo/path" cmds "github.com/ipfs/go-ipfs-cmds" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" ) const ( @@ -60,8 +61,15 @@ Example: return err } - pa := path.New(req.Arguments[0]) - pb := path.New(req.Arguments[1]) + pa, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } + + pb, err := cmdutils.PathOrCidPath(req.Arguments[1]) + if err != nil { + return err + } changes, err := api.Object().Diff(req.Context, pa, pb) if err != nil { @@ -75,12 +83,12 @@ Example: Path: change.Path, } - if change.Before != nil { - out[i].Before = change.Before.Cid() + if (change.Before != path.ImmutablePath{}) { + out[i].Before = change.Before.RootCid() } - if change.After != nil { - out[i].After = change.After.Cid() + if (change.After != path.ImmutablePath{}) { + out[i].After = change.After.RootCid() } } diff --git a/core/commands/object/object.go b/core/commands/object/object.go index febcf347076..8024edfe399 100644 --- a/core/commands/object/object.go +++ b/core/commands/object/object.go @@ -9,10 +9,10 @@ import ( cmds "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" humanize "github.com/dustin/go-humanize" "github.com/ipfs/boxo/coreiface/options" - path "github.com/ipfs/boxo/coreiface/path" dag "github.com/ipfs/boxo/ipld/merkledag" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" @@ -95,7 +95,10 @@ is the raw data of the object. return err } - path := path.New(req.Arguments[0]) + path, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } data, err := api.Object().Data(req.Context, path) if err != nil { @@ -135,9 +138,12 @@ multihash. Provided for legacy reasons. Use 'ipfs dag get' instead. return err } - path := path.New(req.Arguments[0]) + path, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } - rp, err := api.ResolvePath(req.Context, path) + rp, _, err := api.ResolvePath(req.Context, path) if err != nil { return err } @@ -157,7 +163,7 @@ multihash. Provided for legacy reasons. Use 'ipfs dag get' instead. } out := &Object{ - Hash: enc.Encode(rp.Cid()), + Hash: enc.Encode(rp.RootCid()), Links: outLinks, } @@ -212,7 +218,10 @@ DEPRECATED and provided for legacy reasons. Use 'ipfs dag get' instead. return err } - path := path.New(req.Arguments[0]) + path, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } datafieldenc, _ := req.Options[encodingOptionName].(string) if err != nil { @@ -333,7 +342,12 @@ DEPRECATED: Provided for legacy reasons. Modern replacements: return err } - ns, err := api.Object().Stat(req.Context, path.New(req.Arguments[0])) + p, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } + + ns, err := api.Object().Stat(req.Context, p) if err != nil { return err } @@ -434,7 +448,7 @@ DEPRECATED and provided for legacy reasons. Use 'ipfs dag put' instead. return err } - return cmds.EmitOnce(res, &Object{Hash: enc.Encode(p.Cid())}) + return cmds.EmitOnce(res, &Object{Hash: enc.Encode(p.RootCid())}) }, Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *Object) error { diff --git a/core/commands/object/patch.go b/core/commands/object/patch.go index 8ec5b35168b..7e440b1af21 100644 --- a/core/commands/object/patch.go +++ b/core/commands/object/patch.go @@ -9,7 +9,6 @@ import ( "github.com/ipfs/kubo/core/commands/cmdutils" "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" ) var ObjectPatchCmd = &cmds.Command{ @@ -76,7 +75,10 @@ DEPRECATED and provided for legacy reasons. Use 'ipfs add' or 'ipfs files' inste return err } - root := path.New(req.Arguments[0]) + root, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } file, err := cmdenv.GetFileArg(req.Files.Entries()) if err != nil { @@ -88,11 +90,11 @@ DEPRECATED and provided for legacy reasons. Use 'ipfs add' or 'ipfs files' inste return err } - if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil { + if err := cmdutils.CheckCIDSize(req, p.RootCid(), api.Dag()); err != nil { return err } - return cmds.EmitOnce(res, &Object{Hash: p.Cid().String()}) + return cmds.EmitOnce(res, &Object{Hash: p.RootCid().String()}) }, Type: &Object{}, Encoders: cmds.EncoderMap{ @@ -127,7 +129,10 @@ DEPRECATED and provided for legacy reasons. Use 'files cp' and 'dag put' instead return err } - root := path.New(req.Arguments[0]) + root, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } file, err := cmdenv.GetFileArg(req.Files.Entries()) if err != nil { @@ -139,11 +144,11 @@ DEPRECATED and provided for legacy reasons. Use 'files cp' and 'dag put' instead return err } - if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil { + if err := cmdutils.CheckCIDSize(req, p.RootCid(), api.Dag()); err != nil { return err } - return cmds.EmitOnce(res, &Object{Hash: p.Cid().String()}) + return cmds.EmitOnce(res, &Object{Hash: p.RootCid().String()}) }, Type: Object{}, Encoders: cmds.EncoderMap{ @@ -174,7 +179,10 @@ DEPRECATED and provided for legacy reasons. Use 'files rm' instead. return err } - root := path.New(req.Arguments[0]) + root, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } name := req.Arguments[1] p, err := api.Object().RmLink(req.Context, root, name) @@ -182,11 +190,11 @@ DEPRECATED and provided for legacy reasons. Use 'files rm' instead. return err } - if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil { + if err := cmdutils.CheckCIDSize(req, p.RootCid(), api.Dag()); err != nil { return err } - return cmds.EmitOnce(res, &Object{Hash: p.Cid().String()}) + return cmds.EmitOnce(res, &Object{Hash: p.RootCid().String()}) }, Type: Object{}, Encoders: cmds.EncoderMap{ @@ -238,9 +246,17 @@ Use MFS and 'files' commands instead: return err } - root := path.New(req.Arguments[0]) + root, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } + name := req.Arguments[1] - child := path.New(req.Arguments[2]) + + child, err := cmdutils.PathOrCidPath(req.Arguments[2]) + if err != nil { + return err + } create, _ := req.Options[createOptionName].(bool) if err != nil { @@ -253,11 +269,11 @@ Use MFS and 'files' commands instead: return err } - if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil { + if err := cmdutils.CheckCIDSize(req, p.RootCid(), api.Dag()); err != nil { return err } - return cmds.EmitOnce(res, &Object{Hash: p.Cid().String()}) + return cmds.EmitOnce(res, &Object{Hash: p.RootCid().String()}) }, Type: Object{}, Encoders: cmds.EncoderMap{ diff --git a/core/commands/pin/pin.go b/core/commands/pin/pin.go index 9402f5b2ce0..aa4470d700b 100644 --- a/core/commands/pin/pin.go +++ b/core/commands/pin/pin.go @@ -11,7 +11,6 @@ import ( bserv "github.com/ipfs/boxo/blockservice" coreiface "github.com/ipfs/boxo/coreiface" options "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" offline "github.com/ipfs/boxo/exchange/offline" dag "github.com/ipfs/boxo/ipld/merkledag" verifcid "github.com/ipfs/boxo/verifcid" @@ -21,6 +20,7 @@ import ( core "github.com/ipfs/kubo/core" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" e "github.com/ipfs/kubo/core/commands/e" ) @@ -184,7 +184,12 @@ var addPinCmd = &cmds.Command{ func pinAddMany(ctx context.Context, api coreiface.CoreAPI, enc cidenc.Encoder, paths []string, recursive bool) ([]string, error) { added := make([]string, len(paths)) for i, b := range paths { - rp, err := api.ResolvePath(ctx, path.New(b)) + p, err := cmdutils.PathOrCidPath(b) + if err != nil { + return nil, err + } + + rp, _, err := api.ResolvePath(ctx, p) if err != nil { return nil, err } @@ -192,7 +197,7 @@ func pinAddMany(ctx context.Context, api coreiface.CoreAPI, enc cidenc.Encoder, if err := api.Pin().Add(ctx, rp, options.Pin.Recursive(recursive)); err != nil { return nil, err } - added[i] = enc.Encode(rp.Cid()) + added[i] = enc.Encode(rp.RootCid()) } return added, nil @@ -242,12 +247,17 @@ ipfs pin ls -t indirect pins := make([]string, 0, len(req.Arguments)) for _, b := range req.Arguments { - rp, err := api.ResolvePath(req.Context, path.New(b)) + p, err := cmdutils.PathOrCidPath(b) + if err != nil { + return err + } + + rp, _, err := api.ResolvePath(req.Context, p) if err != nil { return err } - id := enc.Encode(rp.Cid()) + id := enc.Encode(rp.RootCid()) pins = append(pins, id) if err := api.Pin().Rm(req.Context, rp, options.Pin.RmRecursive(recursive)); err != nil { return err @@ -453,7 +463,12 @@ func pinLsKeys(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fu } for _, p := range req.Arguments { - rp, err := api.ResolvePath(req.Context, path.New(p)) + p, err := cmdutils.PathOrCidPath(p) + if err != nil { + return err + } + + rp, _, err := api.ResolvePath(req.Context, p) if err != nil { return err } @@ -476,7 +491,7 @@ func pinLsKeys(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fu err = emit(PinLsOutputWrapper{ PinLsObject: PinLsObject{ Type: pinType, - Cid: enc.Encode(rp.Cid()), + Cid: enc.Encode(rp.RootCid()), }, }) if err != nil { @@ -517,7 +532,7 @@ func pinLsAll(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fun err = emit(PinLsOutputWrapper{ PinLsObject: PinLsObject{ Type: p.Type(), - Cid: enc.Encode(p.Path().Cid()), + Cid: enc.Encode(p.Path().RootCid()), }, }) if err != nil { @@ -568,12 +583,22 @@ pin. unpin, _ := req.Options[pinUnpinOptionName].(bool) + fromPath, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } + + toPath, err := cmdutils.PathOrCidPath(req.Arguments[1]) + if err != nil { + return err + } + // Resolve the paths ahead of time so we can return the actual CIDs - from, err := api.ResolvePath(req.Context, path.New(req.Arguments[0])) + from, _, err := api.ResolvePath(req.Context, fromPath) if err != nil { return err } - to, err := api.ResolvePath(req.Context, path.New(req.Arguments[1])) + to, _, err := api.ResolvePath(req.Context, toPath) if err != nil { return err } @@ -583,7 +608,7 @@ pin. return err } - return cmds.EmitOnce(res, &PinOutput{Pins: []string{enc.Encode(from.Cid()), enc.Encode(to.Cid())}}) + return cmds.EmitOnce(res, &PinOutput{Pins: []string{enc.Encode(from.RootCid()), enc.Encode(to.RootCid())}}) }, Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *PinOutput) error { diff --git a/core/commands/pin/remotepin.go b/core/commands/pin/remotepin.go index 2fe615c147b..132532554cc 100644 --- a/core/commands/pin/remotepin.go +++ b/core/commands/pin/remotepin.go @@ -15,13 +15,13 @@ import ( "golang.org/x/sync/errgroup" - path "github.com/ipfs/boxo/coreiface/path" pinclient "github.com/ipfs/boxo/pinning/remote/client" cid "github.com/ipfs/go-cid" cmds "github.com/ipfs/go-ipfs-cmds" logging "github.com/ipfs/go-log" config "github.com/ipfs/kubo/config" "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" fsrepo "github.com/ipfs/kubo/repo/fsrepo" "github.com/libp2p/go-libp2p/core/host" peer "github.com/libp2p/go-libp2p/core/peer" @@ -157,7 +157,12 @@ NOTE: a comma-separated notation is supported in CLI for convenience: if err != nil { return err } - rp, err := api.ResolvePath(ctx, path.New(req.Arguments[0])) + p, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } + + rp, _, err := api.ResolvePath(ctx, p) if err != nil { return err } @@ -177,7 +182,7 @@ NOTE: a comma-separated notation is supported in CLI for convenience: return err } - isInBlockstore, err := node.Blockstore.Has(req.Context, rp.Cid()) + isInBlockstore, err := node.Blockstore.Has(req.Context, rp.RootCid()) if err != nil { return err } @@ -194,7 +199,7 @@ NOTE: a comma-separated notation is supported in CLI for convenience: // Execute remote pin request // TODO: fix panic when pinning service is down - ps, err := c.Add(ctx, rp.Cid(), opts...) + ps, err := c.Add(ctx, rp.RootCid(), opts...) if err != nil { return err } diff --git a/core/commands/refs.go b/core/commands/refs.go index de5206a65c2..3c58fe96113 100644 --- a/core/commands/refs.go +++ b/core/commands/refs.go @@ -8,9 +8,9 @@ import ( "strings" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" iface "github.com/ipfs/boxo/coreiface" - path "github.com/ipfs/boxo/coreiface/path" merkledag "github.com/ipfs/boxo/ipld/merkledag" cid "github.com/ipfs/go-cid" cidenc "github.com/ipfs/go-cidutil/cidenc" @@ -171,11 +171,15 @@ Displays the hashes of all local objects. NOTE: This treats all local objects as func objectsForPaths(ctx context.Context, n iface.CoreAPI, paths []string) ([]cid.Cid, error) { roots := make([]cid.Cid, len(paths)) for i, sp := range paths { - o, err := n.ResolvePath(ctx, path.New(sp)) + p, err := cmdutils.PathOrCidPath(sp) if err != nil { return nil, err } - roots[i] = o.Cid() + o, _, err := n.ResolvePath(ctx, p) + if err != nil { + return nil, err + } + roots[i] = o.RootCid() } return roots, nil } diff --git a/core/commands/resolve.go b/core/commands/resolve.go index 38de57b2109..67450f4cb15 100644 --- a/core/commands/resolve.go +++ b/core/commands/resolve.go @@ -8,14 +8,13 @@ import ( "time" ns "github.com/ipfs/boxo/namesys" + cidenc "github.com/ipfs/go-cidutil/cidenc" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" ncmd "github.com/ipfs/kubo/core/commands/name" options "github.com/ipfs/boxo/coreiface/options" - nsopts "github.com/ipfs/boxo/coreiface/options/namesys" - path "github.com/ipfs/boxo/coreiface/path" - ipfspath "github.com/ipfs/boxo/path" - cidenc "github.com/ipfs/go-cidutil/cidenc" + "github.com/ipfs/boxo/path" cmds "github.com/ipfs/go-ipfs-cmds" ) @@ -87,11 +86,11 @@ Resolve the value of an IPFS DAG path: rc, rcok := req.Options[resolveDhtRecordCountOptionName].(uint) dhtt, dhttok := req.Options[resolveDhtTimeoutOptionName].(string) ropts := []options.NameResolveOption{ - options.Name.ResolveOption(nsopts.Depth(1)), + options.Name.ResolveOption(ns.ResolveWithDepth(1)), } if rcok { - ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtRecordCount(rc))) + ropts = append(ropts, options.Name.ResolveOption(ns.ResolveWithDhtRecordCount(rc))) } if dhttok { d, err := time.ParseDuration(dhtt) @@ -101,14 +100,14 @@ Resolve the value of an IPFS DAG path: if d < 0 { return errors.New("DHT timeout value must be >= 0") } - ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtTimeout(d))) + ropts = append(ropts, options.Name.ResolveOption(ns.ResolveWithDhtTimeout(d))) } p, err := api.Name().Resolve(req.Context, name, ropts...) // ErrResolveRecursion is fine if err != nil && err != ns.ErrResolveRecursion { return err } - return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: ipfspath.Path(p.String())}) + return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: p.String()}) } var enc cidenc.Encoder @@ -128,22 +127,34 @@ Resolve the value of an IPFS DAG path: } } + p, err := cmdutils.PathOrCidPath(name) + if err != nil { + return err + } + // else, ipfs path or ipns with recursive flag - rp, err := api.ResolvePath(req.Context, path.New(name)) + rp, remainder, err := api.ResolvePath(req.Context, p) if err != nil { return err } - encoded := "/" + rp.Namespace() + "/" + enc.Encode(rp.Cid()) - if remainder := rp.Remainder(); remainder != "" { - encoded += "/" + remainder + // Trick to encode path with correct encoding. + encodedPath := "/" + rp.Namespace() + "/" + enc.Encode(rp.RootCid()) + if len(remainder) != 0 { + encodedPath += path.SegmentsToString(remainder...) + } + + // Ensure valid and sanitized. + ep, err := path.NewPath(encodedPath) + if err != nil { + return err } - return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: ipfspath.Path(encoded)}) + return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: ep.String()}) }, Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, rp *ncmd.ResolvedPath) error { - fmt.Fprintln(w, rp.Path.String()) + fmt.Fprintln(w, rp.Path) return nil }), }, diff --git a/core/commands/routing.go b/core/commands/routing.go index c0955456ac7..6d0ddb1c864 100644 --- a/core/commands/routing.go +++ b/core/commands/routing.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "strings" "time" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" @@ -13,7 +14,6 @@ import ( iface "github.com/ipfs/boxo/coreiface" "github.com/ipfs/boxo/coreiface/options" dag "github.com/ipfs/boxo/ipld/merkledag" - path "github.com/ipfs/boxo/path" cid "github.com/ipfs/go-cid" cmds "github.com/ipfs/go-ipfs-cmds" ipld "github.com/ipfs/go-ipld-format" @@ -549,7 +549,7 @@ func printEvent(obj *routing.QueryEvent, out io.Writer, verbose bool, override p } func escapeDhtKey(s string) (string, error) { - parts := path.SplitList(s) + parts := strings.Split(s, "/") if len(parts) != 3 || parts[0] != "" || !(parts[1] == "ipns" || parts[1] == "pk") { @@ -560,5 +560,6 @@ func escapeDhtKey(s string) (string, error) { if err != nil { return "", err } - return path.Join(append(parts[:2], string(k))), nil + + return strings.Join(append(parts[:2], string(k)), "/"), nil } diff --git a/core/commands/tar.go b/core/commands/tar.go index 50bd6794340..e1094a59fb9 100644 --- a/core/commands/tar.go +++ b/core/commands/tar.go @@ -6,9 +6,9 @@ import ( cmds "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" tar "github.com/ipfs/kubo/tar" - path "github.com/ipfs/boxo/coreiface/path" dag "github.com/ipfs/boxo/ipld/merkledag" ) @@ -93,7 +93,12 @@ var tarCatCmd = &cmds.Command{ return err } - root, err := api.ResolveNode(req.Context, path.New(req.Arguments[0])) + p, err := cmdutils.PathOrCidPath(req.Arguments[0]) + if err != nil { + return err + } + + root, err := api.ResolveNode(req.Context, p) if err != nil { return err } diff --git a/core/commands/unixfs/ls.go b/core/commands/unixfs/ls.go index 120b760342f..c2d75c92971 100644 --- a/core/commands/unixfs/ls.go +++ b/core/commands/unixfs/ls.go @@ -7,8 +7,8 @@ import ( "text/tabwriter" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core/commands/cmdutils" - path "github.com/ipfs/boxo/coreiface/path" merkledag "github.com/ipfs/boxo/ipld/merkledag" unixfs "github.com/ipfs/boxo/ipld/unixfs" cmds "github.com/ipfs/go-ipfs-cmds" @@ -96,7 +96,12 @@ If possible, please use 'ipfs ls' instead. for _, p := range paths { ctx := req.Context - merkleNode, err := api.ResolveNode(ctx, path.New(p)) + pth, err := cmdutils.PathOrCidPath(p) + if err != nil { + return err + } + + merkleNode, err := api.ResolveNode(ctx, pth) if err != nil { return err } diff --git a/core/commands/urlstore.go b/core/commands/urlstore.go index 4eec85ede4a..e5dd1ce4d53 100644 --- a/core/commands/urlstore.go +++ b/core/commands/urlstore.go @@ -92,7 +92,7 @@ settings for 'ipfs add'. } size, _ := file.Size() return cmds.EmitOnce(res, &BlockStat{ - Key: enc.Encode(path.Cid()), + Key: enc.Encode(path.RootCid()), Size: int(size), }) }, diff --git a/core/core.go b/core/core.go index c35d3e4457f..40c6808596d 100644 --- a/core/core.go +++ b/core/core.go @@ -47,15 +47,15 @@ import ( ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" + "github.com/ipfs/boxo/bootstrap" "github.com/ipfs/boxo/namesys" ipnsrp "github.com/ipfs/boxo/namesys/republisher" + "github.com/ipfs/boxo/peering" "github.com/ipfs/kubo/config" - "github.com/ipfs/kubo/core/bootstrap" "github.com/ipfs/kubo/core/node" "github.com/ipfs/kubo/core/node/libp2p" "github.com/ipfs/kubo/fuse/mount" "github.com/ipfs/kubo/p2p" - "github.com/ipfs/kubo/peering" "github.com/ipfs/kubo/repo" irouting "github.com/ipfs/kubo/routing" ) @@ -76,35 +76,39 @@ type IpfsNode struct { PNetFingerprint libp2p.PNetFingerprint `optional:"true"` // fingerprint of private network // Services - Peerstore pstore.Peerstore `optional:"true"` // storage for other Peer instances - Blockstore bstore.GCBlockstore // the block store (lower level) - Filestore *filestore.Filestore `optional:"true"` // the filestore blockstore - BaseBlocks node.BaseBlocks // the raw blockstore, no filestore wrapping - GCLocker bstore.GCLocker // the locker used to protect the blockstore during gc - Blocks bserv.BlockService // the block service, get/add blocks. - DAG ipld.DAGService // the merkle dag service, get/add objects. - IPLDFetcherFactory fetcher.Factory `name:"ipldFetcher"` // fetcher that paths over the IPLD data model - UnixFSFetcherFactory fetcher.Factory `name:"unixfsFetcher"` // fetcher that interprets UnixFS data - Reporter *metrics.BandwidthCounter `optional:"true"` - Discovery mdns.Service `optional:"true"` - FilesRoot *mfs.Root - RecordValidator record.Validator + Peerstore pstore.Peerstore `optional:"true"` // storage for other Peer instances + Blockstore bstore.GCBlockstore // the block store (lower level) + Filestore *filestore.Filestore `optional:"true"` // the filestore blockstore + BaseBlocks node.BaseBlocks // the raw blockstore, no filestore wrapping + GCLocker bstore.GCLocker // the locker used to protect the blockstore during gc + Blocks bserv.BlockService // the block service, get/add blocks. + DAG ipld.DAGService // the merkle dag service, get/add objects. + IPLDFetcherFactory fetcher.Factory `name:"ipldFetcher"` // fetcher that paths over the IPLD data model + UnixFSFetcherFactory fetcher.Factory `name:"unixfsFetcher"` // fetcher that interprets UnixFS data + OfflineIPLDFetcherFactory fetcher.Factory `name:"offlineIpldFetcher"` // fetcher that paths over the IPLD data model without fetching new blocks + OfflineUnixFSFetcherFactory fetcher.Factory `name:"offlineUnixfsFetcher"` // fetcher that interprets UnixFS data without fetching new blocks + Reporter *metrics.BandwidthCounter `optional:"true"` + Discovery mdns.Service `optional:"true"` + FilesRoot *mfs.Root + RecordValidator record.Validator // Online - PeerHost p2phost.Host `optional:"true"` // the network host (server+client) - Peering *peering.PeeringService `optional:"true"` - Filters *ma.Filters `optional:"true"` - Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper - Routing irouting.ProvideManyRouter `optional:"true"` // the routing system. recommend ipfs-dht - DNSResolver *madns.Resolver // the DNS resolver - IPLDPathResolver pathresolver.Resolver `name:"ipldPathResolver"` // The IPLD path resolver - UnixFSPathResolver pathresolver.Resolver `name:"unixFSPathResolver"` // The UnixFS path resolver - Exchange exchange.Interface // the block exchange + strategy (bitswap) - Namesys namesys.NameSystem // the name system, resolves paths to hashes - Provider provider.System // the value provider system - IpnsRepub *ipnsrp.Republisher `optional:"true"` - GraphExchange graphsync.GraphExchange `optional:"true"` - ResourceManager network.ResourceManager `optional:"true"` + PeerHost p2phost.Host `optional:"true"` // the network host (server+client) + Peering *peering.PeeringService `optional:"true"` + Filters *ma.Filters `optional:"true"` + Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper + Routing irouting.ProvideManyRouter `optional:"true"` // the routing system. recommend ipfs-dht + DNSResolver *madns.Resolver // the DNS resolver + IPLDPathResolver pathresolver.Resolver `name:"ipldPathResolver"` // The IPLD path resolver + UnixFSPathResolver pathresolver.Resolver `name:"unixFSPathResolver"` // The UnixFS path resolver + OfflineIPLDPathResolver pathresolver.Resolver `name:"offlineIpldPathResolver"` // The IPLD path resolver that uses only locally available blocks + OfflineUnixFSPathResolver pathresolver.Resolver `name:"offlineUnixFSPathResolver"` // The UnixFS path resolver that uses only locally available blocks + Exchange exchange.Interface // the block exchange + strategy (bitswap) + Namesys namesys.NameSystem // the name system, resolves paths to hashes + Provider provider.System // the value provider system + IpnsRepub *ipnsrp.Republisher `optional:"true"` + GraphExchange graphsync.GraphExchange `optional:"true"` + ResourceManager network.ResourceManager `optional:"true"` PubSub *pubsub.PubSub `optional:"true"` PSRouter *psrouter.PubsubValueStore `optional:"true"` diff --git a/core/coreapi/block.go b/core/coreapi/block.go index 55810de7e9d..ffbe89c8bf6 100644 --- a/core/coreapi/block.go +++ b/core/coreapi/block.go @@ -8,7 +8,7 @@ import ( coreiface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - path "github.com/ipfs/boxo/coreiface/path" + "github.com/ipfs/boxo/path" pin "github.com/ipfs/boxo/pinning/pinner" blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" @@ -22,7 +22,7 @@ import ( type BlockAPI CoreAPI type BlockStat struct { - path path.Resolved + path path.ImmutablePath size int } @@ -68,18 +68,18 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc } } - return &BlockStat{path: path.IpldPath(b.Cid()), size: len(data)}, nil + return &BlockStat{path: path.FromCid(b.Cid()), size: len(data)}, nil } func (api *BlockAPI) Get(ctx context.Context, p path.Path) (io.Reader, error) { ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Get", trace.WithAttributes(attribute.String("path", p.String()))) defer span.End() - rp, err := api.core().ResolvePath(ctx, p) + rp, _, err := api.core().ResolvePath(ctx, p) if err != nil { return nil, err } - b, err := api.blocks.GetBlock(ctx, rp.Cid()) + b, err := api.blocks.GetBlock(ctx, rp.RootCid()) if err != nil { return nil, err } @@ -91,7 +91,7 @@ func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRm ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Rm", trace.WithAttributes(attribute.String("path", p.String()))) defer span.End() - rp, err := api.core().ResolvePath(ctx, p) + rp, _, err := api.core().ResolvePath(ctx, p) if err != nil { return err } @@ -100,7 +100,7 @@ func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRm if err != nil { return err } - cids := []cid.Cid{rp.Cid()} + cids := []cid.Cid{rp.RootCid()} o := util.RmBlocksOpts{Force: settings.Force} out, err := util.RmBlocks(ctx, api.blockstore, api.pinning, cids, o) @@ -132,18 +132,18 @@ func (api *BlockAPI) Stat(ctx context.Context, p path.Path) (coreiface.BlockStat ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Stat", trace.WithAttributes(attribute.String("path", p.String()))) defer span.End() - rp, err := api.core().ResolvePath(ctx, p) + rp, _, err := api.core().ResolvePath(ctx, p) if err != nil { return nil, err } - b, err := api.blocks.GetBlock(ctx, rp.Cid()) + b, err := api.blocks.GetBlock(ctx, rp.RootCid()) if err != nil { return nil, err } return &BlockStat{ - path: path.IpldPath(b.Cid()), + path: path.FromCid(b.Cid()), size: len(b.RawData()), }, nil } @@ -152,7 +152,7 @@ func (bs *BlockStat) Size() int { return bs.size } -func (bs *BlockStat) Path() path.Resolved { +func (bs *BlockStat) Path() path.ImmutablePath { return bs.path } diff --git a/core/coreapi/coreapi.go b/core/coreapi/coreapi.go index 5a7e321a9c6..81d05b58d49 100644 --- a/core/coreapi/coreapi.go +++ b/core/coreapi/coreapi.go @@ -1,15 +1,12 @@ /* +**NOTE: this package is experimental.** + Package coreapi provides direct access to the core commands in IPFS. If you are embedding IPFS directly in your Go program, this package is the public interface you should use to read and write files or otherwise control IPFS. -If you are running IPFS as a separate process, you should use `go-ipfs-api` to -work with it via HTTP. As we finalize the interfaces here, `go-ipfs-api` will -transparently adopt them so you can use the same code with either package. - -**NOTE: this package is experimental.** `go-ipfs` has mainly been developed -as a standalone application and library-style use of this package is still new. -Interfaces here aren't yet completely stable. +If you are running IPFS as a separate process, you should use `client/rpc` to +work with it via HTTP. */ package coreapi diff --git a/core/coreapi/dht.go b/core/coreapi/dht.go index 4feb8a76c07..c960ee0844c 100644 --- a/core/coreapi/dht.go +++ b/core/coreapi/dht.go @@ -8,9 +8,9 @@ import ( blockstore "github.com/ipfs/boxo/blockstore" coreiface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - path "github.com/ipfs/boxo/coreiface/path" offline "github.com/ipfs/boxo/exchange/offline" dag "github.com/ipfs/boxo/ipld/merkledag" + "github.com/ipfs/boxo/path" cid "github.com/ipfs/go-cid" cidutil "github.com/ipfs/go-cidutil" "github.com/ipfs/kubo/tracing" @@ -53,7 +53,7 @@ func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopt return nil, err } - rp, err := api.core().ResolvePath(ctx, p) + rp, _, err := api.core().ResolvePath(ctx, p) if err != nil { return nil, err } @@ -63,7 +63,7 @@ func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopt return nil, fmt.Errorf("number of providers must be greater than 0") } - pchan := api.routing.FindProvidersAsync(ctx, rp.Cid(), numProviders) + pchan := api.routing.FindProvidersAsync(ctx, rp.RootCid(), numProviders) return pchan, nil } @@ -82,12 +82,12 @@ func (api *DhtAPI) Provide(ctx context.Context, path path.Path, opts ...caopts.D return err } - rp, err := api.core().ResolvePath(ctx, path) + rp, _, err := api.core().ResolvePath(ctx, path) if err != nil { return err } - c := rp.Cid() + c := rp.RootCid() has, err := api.blockstore.Has(ctx, c) if err != nil { diff --git a/core/coreapi/key.go b/core/coreapi/key.go index 925748a37d2..4c914ff3d20 100644 --- a/core/coreapi/key.go +++ b/core/coreapi/key.go @@ -9,8 +9,8 @@ import ( coreiface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - path "github.com/ipfs/boxo/coreiface/path" - ipfspath "github.com/ipfs/boxo/path" + "github.com/ipfs/boxo/ipns" + "github.com/ipfs/boxo/path" "github.com/ipfs/kubo/tracing" crypto "github.com/libp2p/go-libp2p/core/crypto" peer "github.com/libp2p/go-libp2p/core/peer" @@ -23,6 +23,19 @@ type KeyAPI CoreAPI type key struct { name string peerID peer.ID + path path.Path +} + +func newKey(name string, pid peer.ID) (*key, error) { + p, err := path.NewPath("/ipns/" + ipns.NameFromPeer(pid).String()) + if err != nil { + return nil, err + } + return &key{ + name: name, + peerID: pid, + path: p, + }, nil } // Name returns the key name @@ -32,7 +45,7 @@ func (k *key) Name() string { // Path returns the path of the key. func (k *key) Path() path.Path { - return path.New(ipfspath.Join([]string{"/ipns", coreiface.FormatKeyID(k.peerID)})) + return k.path } // ID returns key PeerID @@ -98,7 +111,7 @@ func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.Key return nil, err } - return &key{name, pid}, nil + return newKey(name, pid) } // List returns a list keys stored in keystore. @@ -114,7 +127,10 @@ func (api *KeyAPI) List(ctx context.Context) ([]coreiface.Key, error) { sort.Strings(keys) out := make([]coreiface.Key, len(keys)+1) - out[0] = &key{"self", api.identity} + out[0], err = newKey("self", api.identity) + if err != nil { + return nil, err + } for n, k := range keys { privKey, err := api.repo.Keystore().Get(k) @@ -129,7 +145,10 @@ func (api *KeyAPI) List(ctx context.Context) ([]coreiface.Key, error) { return nil, err } - out[n+1] = &key{k, pid} + out[n+1], err = newKey(k, pid) + if err != nil { + return nil, err + } } return out, nil } @@ -171,7 +190,8 @@ func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, o // This is important, because future code will delete key `oldName` // even if it is the same as newName. if newName == oldName { - return &key{oldName, pid}, false, nil + k, err := newKey(oldName, pid) + return k, false, err } overwrite := false @@ -195,7 +215,13 @@ func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, o return nil, false, err } - return &key{newName, pid}, overwrite, ks.Delete(oldName) + err = ks.Delete(oldName) + if err != nil { + return nil, false, err + } + + k, err := newKey(newName, pid) + return k, overwrite, err } // Remove removes keys from keystore. Returns ipns path of the removed key. @@ -226,7 +252,7 @@ func (api *KeyAPI) Remove(ctx context.Context, name string) (coreiface.Key, erro return nil, err } - return &key{"", pid}, nil + return newKey("", pid) } func (api *KeyAPI) Self(ctx context.Context) (coreiface.Key, error) { @@ -234,5 +260,5 @@ func (api *KeyAPI) Self(ctx context.Context) (coreiface.Key, error) { return nil, errors.New("identity not loaded") } - return &key{"self", api.identity}, nil + return newKey("self", api.identity) } diff --git a/core/coreapi/name.go b/core/coreapi/name.go index 3bf59a00c4e..4f6c1a3cc1e 100644 --- a/core/coreapi/name.go +++ b/core/coreapi/name.go @@ -15,9 +15,7 @@ import ( coreiface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - nsopts "github.com/ipfs/boxo/coreiface/options/namesys" - path "github.com/ipfs/boxo/coreiface/path" - ipath "github.com/ipfs/boxo/path" + "github.com/ipfs/boxo/path" ci "github.com/libp2p/go-libp2p/core/crypto" peer "github.com/libp2p/go-libp2p/core/peer" ) @@ -51,11 +49,6 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam return ipns.Name{}, err } - pth, err := ipath.ParsePath(p.String()) - if err != nil { - return ipns.Name{}, err - } - k, err := keylookup(api.privateKey, api.repo.Keystore(), options.Key) if err != nil { return ipns.Name{}, err @@ -63,16 +56,16 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam eol := time.Now().Add(options.ValidTime) - publishOptions := []nsopts.PublishOption{ - nsopts.PublishWithEOL(eol), - nsopts.PublishCompatibleWithV1(options.CompatibleWithV1), + publishOptions := []namesys.PublishOption{ + namesys.PublishWithEOL(eol), + namesys.PublishWithIPNSOption(ipns.WithV1Compatibility(options.CompatibleWithV1)), } if options.TTL != nil { - publishOptions = append(publishOptions, nsopts.PublishWithTTL(*options.TTL)) + publishOptions = append(publishOptions, namesys.PublishWithTTL(*options.TTL)) } - err = api.namesys.Publish(ctx, k, pth, publishOptions...) + err = api.namesys.Publish(ctx, k, p, publishOptions...) if err != nil { return ipns.Name{}, err } @@ -115,12 +108,17 @@ func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.Name name = "/ipns/" + name } + p, err := path.NewPath(name) + if err != nil { + return nil, err + } + out := make(chan coreiface.IpnsResult) go func() { defer close(out) - for res := range resolver.ResolveAsync(ctx, name, options.ResolveOpts...) { + for res := range resolver.ResolveAsync(ctx, p, options.ResolveOpts...) { select { - case out <- coreiface.IpnsResult{Path: path.New(res.Path.String()), Err: res.Err}: + case out <- coreiface.IpnsResult{Path: res.Path, Err: res.Err}: case <-ctx.Done(): return } diff --git a/core/coreapi/object.go b/core/coreapi/object.go index 1b1caea6575..3c63372e01d 100644 --- a/core/coreapi/object.go +++ b/core/coreapi/object.go @@ -12,10 +12,10 @@ import ( coreiface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - ipath "github.com/ipfs/boxo/coreiface/path" dag "github.com/ipfs/boxo/ipld/merkledag" "github.com/ipfs/boxo/ipld/merkledag/dagutils" ft "github.com/ipfs/boxo/ipld/unixfs" + "github.com/ipfs/boxo/path" pin "github.com/ipfs/boxo/pinning/pinner" cid "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" @@ -65,13 +65,13 @@ func (api *ObjectAPI) New(ctx context.Context, opts ...caopts.ObjectNewOption) ( return n, nil } -func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.ObjectPutOption) (ipath.Resolved, error) { +func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.ObjectPutOption) (path.ImmutablePath, error) { ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Put") defer span.End() options, err := caopts.ObjectPutOptions(opts...) if err != nil { - return nil, err + return path.ImmutablePath{}, err } span.SetAttributes( attribute.Bool("pin", options.Pin), @@ -81,7 +81,7 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj data, err := io.ReadAll(io.LimitReader(src, inputLimit+10)) if err != nil { - return nil, err + return path.ImmutablePath{}, err } var dagnode *dag.ProtoNode @@ -92,12 +92,12 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj decoder.DisallowUnknownFields() err = decoder.Decode(node) if err != nil { - return nil, err + return path.ImmutablePath{}, err } dagnode, err = deserializeNode(node, options.DataType) if err != nil { - return nil, err + return path.ImmutablePath{}, err } case "protobuf": @@ -107,20 +107,20 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj node := new(Node) err = xml.Unmarshal(data, node) if err != nil { - return nil, err + return path.ImmutablePath{}, err } dagnode, err = deserializeNode(node, options.DataType) if err != nil { - return nil, err + return path.ImmutablePath{}, err } default: - return nil, errors.New("unknown object encoding") + return path.ImmutablePath{}, errors.New("unknown object encoding") } if err != nil { - return nil, err + return path.ImmutablePath{}, err } if options.Pin { @@ -129,30 +129,30 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj err = api.dag.Add(ctx, dagnode) if err != nil { - return nil, err + return path.ImmutablePath{}, err } if options.Pin { if err := api.pinning.PinWithMode(ctx, dagnode.Cid(), pin.Recursive); err != nil { - return nil, err + return path.ImmutablePath{}, err } err = api.pinning.Flush(ctx) if err != nil { - return nil, err + return path.ImmutablePath{}, err } } - return ipath.IpfsPath(dagnode.Cid()), nil + return path.FromCid(dagnode.Cid()), nil } -func (api *ObjectAPI) Get(ctx context.Context, path ipath.Path) (ipld.Node, error) { +func (api *ObjectAPI) Get(ctx context.Context, path path.Path) (ipld.Node, error) { ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Get", trace.WithAttributes(attribute.String("path", path.String()))) defer span.End() return api.core().ResolveNode(ctx, path) } -func (api *ObjectAPI) Data(ctx context.Context, path ipath.Path) (io.Reader, error) { +func (api *ObjectAPI) Data(ctx context.Context, path path.Path) (io.Reader, error) { ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Data", trace.WithAttributes(attribute.String("path", path.String()))) defer span.End() @@ -169,7 +169,7 @@ func (api *ObjectAPI) Data(ctx context.Context, path ipath.Path) (io.Reader, err return bytes.NewReader(pbnd.Data()), nil } -func (api *ObjectAPI) Links(ctx context.Context, path ipath.Path) ([]*ipld.Link, error) { +func (api *ObjectAPI) Links(ctx context.Context, path path.Path) ([]*ipld.Link, error) { ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Links", trace.WithAttributes(attribute.String("path", path.String()))) defer span.End() @@ -187,7 +187,7 @@ func (api *ObjectAPI) Links(ctx context.Context, path ipath.Path) ([]*ipld.Link, return out, nil } -func (api *ObjectAPI) Stat(ctx context.Context, path ipath.Path) (*coreiface.ObjectStat, error) { +func (api *ObjectAPI) Stat(ctx context.Context, path path.Path) (*coreiface.ObjectStat, error) { ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Stat", trace.WithAttributes(attribute.String("path", path.String()))) defer span.End() @@ -213,7 +213,7 @@ func (api *ObjectAPI) Stat(ctx context.Context, path ipath.Path) (*coreiface.Obj return out, nil } -func (api *ObjectAPI) AddLink(ctx context.Context, base ipath.Path, name string, child ipath.Path, opts ...caopts.ObjectAddLinkOption) (ipath.Resolved, error) { +func (api *ObjectAPI) AddLink(ctx context.Context, base path.Path, name string, child path.Path, opts ...caopts.ObjectAddLinkOption) (path.ImmutablePath, error) { ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "AddLink", trace.WithAttributes( attribute.String("base", base.String()), attribute.String("name", name), @@ -223,23 +223,23 @@ func (api *ObjectAPI) AddLink(ctx context.Context, base ipath.Path, name string, options, err := caopts.ObjectAddLinkOptions(opts...) if err != nil { - return nil, err + return path.ImmutablePath{}, err } span.SetAttributes(attribute.Bool("create", options.Create)) baseNd, err := api.core().ResolveNode(ctx, base) if err != nil { - return nil, err + return path.ImmutablePath{}, err } childNd, err := api.core().ResolveNode(ctx, child) if err != nil { - return nil, err + return path.ImmutablePath{}, err } basePb, ok := baseNd.(*dag.ProtoNode) if !ok { - return nil, dag.ErrNotProtobuf + return path.ImmutablePath{}, dag.ErrNotProtobuf } var createfunc func() *dag.ProtoNode @@ -251,18 +251,18 @@ func (api *ObjectAPI) AddLink(ctx context.Context, base ipath.Path, name string, err = e.InsertNodeAtPath(ctx, name, childNd, createfunc) if err != nil { - return nil, err + return path.ImmutablePath{}, err } nnode, err := e.Finalize(ctx, api.dag) if err != nil { - return nil, err + return path.ImmutablePath{}, err } - return ipath.IpfsPath(nnode.Cid()), nil + return path.FromCid(nnode.Cid()), nil } -func (api *ObjectAPI) RmLink(ctx context.Context, base ipath.Path, link string) (ipath.Resolved, error) { +func (api *ObjectAPI) RmLink(ctx context.Context, base path.Path, link string) (path.ImmutablePath, error) { ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "RmLink", trace.WithAttributes( attribute.String("base", base.String()), attribute.String("link", link)), @@ -271,57 +271,57 @@ func (api *ObjectAPI) RmLink(ctx context.Context, base ipath.Path, link string) baseNd, err := api.core().ResolveNode(ctx, base) if err != nil { - return nil, err + return path.ImmutablePath{}, err } basePb, ok := baseNd.(*dag.ProtoNode) if !ok { - return nil, dag.ErrNotProtobuf + return path.ImmutablePath{}, dag.ErrNotProtobuf } e := dagutils.NewDagEditor(basePb, api.dag) err = e.RmLink(ctx, link) if err != nil { - return nil, err + return path.ImmutablePath{}, err } nnode, err := e.Finalize(ctx, api.dag) if err != nil { - return nil, err + return path.ImmutablePath{}, err } - return ipath.IpfsPath(nnode.Cid()), nil + return path.FromCid(nnode.Cid()), nil } -func (api *ObjectAPI) AppendData(ctx context.Context, path ipath.Path, r io.Reader) (ipath.Resolved, error) { +func (api *ObjectAPI) AppendData(ctx context.Context, path path.Path, r io.Reader) (path.ImmutablePath, error) { ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "AppendData", trace.WithAttributes(attribute.String("path", path.String()))) defer span.End() return api.patchData(ctx, path, r, true) } -func (api *ObjectAPI) SetData(ctx context.Context, path ipath.Path, r io.Reader) (ipath.Resolved, error) { +func (api *ObjectAPI) SetData(ctx context.Context, path path.Path, r io.Reader) (path.ImmutablePath, error) { ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "SetData", trace.WithAttributes(attribute.String("path", path.String()))) defer span.End() return api.patchData(ctx, path, r, false) } -func (api *ObjectAPI) patchData(ctx context.Context, path ipath.Path, r io.Reader, appendData bool) (ipath.Resolved, error) { - nd, err := api.core().ResolveNode(ctx, path) +func (api *ObjectAPI) patchData(ctx context.Context, p path.Path, r io.Reader, appendData bool) (path.ImmutablePath, error) { + nd, err := api.core().ResolveNode(ctx, p) if err != nil { - return nil, err + return path.ImmutablePath{}, err } pbnd, ok := nd.(*dag.ProtoNode) if !ok { - return nil, dag.ErrNotProtobuf + return path.ImmutablePath{}, dag.ErrNotProtobuf } data, err := io.ReadAll(r) if err != nil { - return nil, err + return path.ImmutablePath{}, err } if appendData { @@ -331,13 +331,13 @@ func (api *ObjectAPI) patchData(ctx context.Context, path ipath.Path, r io.Reade err = api.dag.Add(ctx, pbnd) if err != nil { - return nil, err + return path.ImmutablePath{}, err } - return ipath.IpfsPath(pbnd.Cid()), nil + return path.FromCid(pbnd.Cid()), nil } -func (api *ObjectAPI) Diff(ctx context.Context, before ipath.Path, after ipath.Path) ([]coreiface.ObjectChange, error) { +func (api *ObjectAPI) Diff(ctx context.Context, before path.Path, after path.Path) ([]coreiface.ObjectChange, error) { ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Diff", trace.WithAttributes( attribute.String("before", before.String()), attribute.String("after", after.String()), @@ -367,11 +367,11 @@ func (api *ObjectAPI) Diff(ctx context.Context, before ipath.Path, after ipath.P } if change.Before.Defined() { - out[i].Before = ipath.IpfsPath(change.Before) + out[i].Before = path.FromCid(change.Before) } if change.After.Defined() { - out[i].After = ipath.IpfsPath(change.After) + out[i].After = path.FromCid(change.After) } } diff --git a/core/coreapi/path.go b/core/coreapi/path.go index db07c64281a..1d8e868e463 100644 --- a/core/coreapi/path.go +++ b/core/coreapi/path.go @@ -2,20 +2,18 @@ package coreapi import ( "context" + "errors" "fmt" - gopath "path" - "github.com/ipfs/boxo/namesys/resolve" + "github.com/ipfs/boxo/namesys" "github.com/ipfs/kubo/tracing" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" coreiface "github.com/ipfs/boxo/coreiface" - path "github.com/ipfs/boxo/coreiface/path" - ipfspath "github.com/ipfs/boxo/path" + "github.com/ipfs/boxo/path" ipfspathresolver "github.com/ipfs/boxo/path/resolver" - "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" ) @@ -25,12 +23,12 @@ func (api *CoreAPI) ResolveNode(ctx context.Context, p path.Path) (ipld.Node, er ctx, span := tracing.Span(ctx, "CoreAPI", "ResolveNode", trace.WithAttributes(attribute.String("path", p.String()))) defer span.End() - rp, err := api.ResolvePath(ctx, p) + rp, _, err := api.ResolvePath(ctx, p) if err != nil { return nil, err } - node, err := api.dag.Get(ctx, rp.Cid()) + node, err := api.dag.Get(ctx, rp.RootCid()) if err != nil { return nil, err } @@ -39,45 +37,50 @@ func (api *CoreAPI) ResolveNode(ctx context.Context, p path.Path) (ipld.Node, er // ResolvePath resolves the path `p` using Unixfs resolver, returns the // resolved path. -func (api *CoreAPI) ResolvePath(ctx context.Context, p path.Path) (path.Resolved, error) { +func (api *CoreAPI) ResolvePath(ctx context.Context, p path.Path) (path.ImmutablePath, []string, error) { ctx, span := tracing.Span(ctx, "CoreAPI", "ResolvePath", trace.WithAttributes(attribute.String("path", p.String()))) defer span.End() - if _, ok := p.(path.Resolved); ok { - return p.(path.Resolved), nil - } - if err := p.IsValid(); err != nil { - return nil, err - } - - ipath := ipfspath.Path(p.String()) - ipath, err := resolve.ResolveIPNS(ctx, api.namesys, ipath) - if err == resolve.ErrNoNamesys { - return nil, coreiface.ErrOffline + res, err := namesys.Resolve(ctx, api.namesys, p) + if errors.Is(err, namesys.ErrNoNamesys) { + return path.ImmutablePath{}, nil, coreiface.ErrOffline } else if err != nil { - return nil, err - } - - if ipath.Segments()[0] != "ipfs" && ipath.Segments()[0] != "ipld" { - return nil, fmt.Errorf("unsupported path namespace: %s", p.Namespace()) + return path.ImmutablePath{}, nil, err } + p = res.Path var resolver ipfspathresolver.Resolver - if ipath.Segments()[0] == "ipld" { + switch p.Namespace() { + case path.IPLDNamespace: resolver = api.ipldPathResolver - } else { + case path.IPFSNamespace: resolver = api.unixFSPathResolver + default: + return path.ImmutablePath{}, nil, fmt.Errorf("unsupported path namespace: %s", p.Namespace()) } - node, rest, err := resolver.ResolveToLastNode(ctx, ipath) + imPath, err := path.NewImmutablePath(p) if err != nil { - return nil, err + return path.ImmutablePath{}, nil, err } - root, err := cid.Parse(ipath.Segments()[1]) + node, remainder, err := resolver.ResolveToLastNode(ctx, imPath) if err != nil { - return nil, err + return path.ImmutablePath{}, nil, err + } + + segments := []string{p.Namespace(), node.String()} + segments = append(segments, remainder...) + + p, err = path.NewPathFromSegments(segments...) + if err != nil { + return path.ImmutablePath{}, nil, err + } + + imPath, err = path.NewImmutablePath(p) + if err != nil { + return path.ImmutablePath{}, nil, err } - return path.NewResolvedPath(ipath, node, root, gopath.Join(rest...)), nil + return imPath, remainder, nil } diff --git a/core/coreapi/pin.go b/core/coreapi/pin.go index ec2cedb83fd..7c33b3ee0a7 100644 --- a/core/coreapi/pin.go +++ b/core/coreapi/pin.go @@ -7,9 +7,9 @@ import ( bserv "github.com/ipfs/boxo/blockservice" coreiface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" offline "github.com/ipfs/boxo/exchange/offline" "github.com/ipfs/boxo/ipld/merkledag" + "github.com/ipfs/boxo/path" pin "github.com/ipfs/boxo/pinning/pinner" "github.com/ipfs/go-cid" "go.opentelemetry.io/otel/attribute" @@ -74,7 +74,7 @@ func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.Pin ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "IsPinned", trace.WithAttributes(attribute.String("path", p.String()))) defer span.End() - resolved, err := api.core().ResolvePath(ctx, p) + resolved, _, err := api.core().ResolvePath(ctx, p) if err != nil { return "", false, fmt.Errorf("error resolving path: %s", err) } @@ -91,7 +91,7 @@ func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.Pin return "", false, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.WithType) } - return api.pinning.IsPinnedWithType(ctx, resolved.Cid(), mode) + return api.pinning.IsPinnedWithType(ctx, resolved.RootCid(), mode) } // Rm pin rm api @@ -99,7 +99,7 @@ func (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOpti ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Rm", trace.WithAttributes(attribute.String("path", p.String()))) defer span.End() - rp, err := api.core().ResolvePath(ctx, p) + rp, _, err := api.core().ResolvePath(ctx, p) if err != nil { return err } @@ -115,7 +115,7 @@ func (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOpti // to take a lock to prevent a concurrent garbage collection defer api.blockstore.PinLock(ctx).Unlock(ctx) - if err = api.pinning.Unpin(ctx, rp.Cid(), settings.Recursive); err != nil { + if err = api.pinning.Unpin(ctx, rp.RootCid(), settings.Recursive); err != nil { return err } @@ -136,19 +136,19 @@ func (api *PinAPI) Update(ctx context.Context, from path.Path, to path.Path, opt span.SetAttributes(attribute.Bool("unpin", settings.Unpin)) - fp, err := api.core().ResolvePath(ctx, from) + fp, _, err := api.core().ResolvePath(ctx, from) if err != nil { return err } - tp, err := api.core().ResolvePath(ctx, to) + tp, _, err := api.core().ResolvePath(ctx, to) if err != nil { return err } defer api.blockstore.PinLock(ctx).Unlock(ctx) - err = api.pinning.Update(ctx, fp.Cid(), tp.Cid(), settings.Unpin) + err = api.pinning.Update(ctx, fp.RootCid(), tp.RootCid(), settings.Unpin) if err != nil { return err } @@ -165,7 +165,7 @@ type pinStatus struct { // BadNode is used in PinVerifyRes type badNode struct { - path path.Resolved + path path.ImmutablePath err error } @@ -181,7 +181,7 @@ func (s *pinStatus) Err() error { return s.err } -func (n *badNode) Path() path.Resolved { +func (n *badNode) Path() path.ImmutablePath { return n.path } @@ -210,7 +210,7 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro links, err := getLinks(ctx, root) if err != nil { status := &pinStatus{ok: false, cid: root} - status.badNodes = []coreiface.BadPinNode{&badNode{path: path.IpldPath(root), err: err}} + status.badNodes = []coreiface.BadPinNode{&badNode{path: path.FromCid(root), err: err}} visited[root] = status return status } @@ -251,11 +251,11 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro type pinInfo struct { pinType string - path path.Resolved + path path.ImmutablePath err error } -func (p *pinInfo) Path() path.Resolved { +func (p *pinInfo) Path() path.ImmutablePath { return p.path } @@ -281,7 +281,7 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac select { case out <- &pinInfo{ pinType: typeStr, - path: path.IpldPath(c), + path: path.FromCid(c), }: case <-ctx.Done(): return ctx.Err() diff --git a/core/coreapi/routing.go b/core/coreapi/routing.go index 95b50aa631d..3b28e0472c1 100644 --- a/core/coreapi/routing.go +++ b/core/coreapi/routing.go @@ -3,10 +3,10 @@ package coreapi import ( "context" "errors" + "strings" coreiface "github.com/ipfs/boxo/coreiface" caopts "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/path" peer "github.com/libp2p/go-libp2p/core/peer" ) @@ -45,7 +45,7 @@ func (r *RoutingAPI) Put(ctx context.Context, key string, value []byte, opts ... } func normalizeKey(s string) (string, error) { - parts := path.SplitList(s) + parts := strings.Split(s, "/") if len(parts) != 3 || parts[0] != "" || !(parts[1] == "ipns" || parts[1] == "pk") { @@ -56,5 +56,5 @@ func normalizeKey(s string) (string, error) { if err != nil { return "", err } - return path.Join(append(parts[:2], string(k))), nil + return strings.Join(append(parts[:2], string(k)), "/"), nil } diff --git a/core/coreapi/test/api_test.go b/core/coreapi/test/api_test.go index 3ae74b97e9a..d9591f83522 100644 --- a/core/coreapi/test/api_test.go +++ b/core/coreapi/test/api_test.go @@ -8,10 +8,10 @@ import ( "path/filepath" "testing" + "github.com/ipfs/boxo/bootstrap" "github.com/ipfs/boxo/filestore" keystore "github.com/ipfs/boxo/keystore" "github.com/ipfs/kubo/core" - "github.com/ipfs/kubo/core/bootstrap" "github.com/ipfs/kubo/core/coreapi" mock "github.com/ipfs/kubo/core/mock" "github.com/ipfs/kubo/core/node/libp2p" diff --git a/core/coreapi/test/path_test.go b/core/coreapi/test/path_test.go index 0dce7262799..6ba80423d35 100644 --- a/core/coreapi/test/path_test.go +++ b/core/coreapi/test/path_test.go @@ -7,10 +7,10 @@ import ( "time" "github.com/ipfs/boxo/coreiface/options" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" "github.com/ipfs/boxo/ipld/merkledag" uio "github.com/ipfs/boxo/ipld/unixfs/io" + "github.com/ipfs/boxo/path" "github.com/ipld/go-ipld-prime" ) @@ -45,7 +45,7 @@ func TestPathUnixFSHAMTPartial(t *testing.T) { } // Get the root of the directory - nd, err := a.Dag().Get(ctx, r.Cid()) + nd, err := a.Dag().Get(ctx, r.RootCid()) if err != nil { t.Fatal(err) } @@ -55,7 +55,7 @@ func TestPathUnixFSHAMTPartial(t *testing.T) { pbNode := nd.(*merkledag.ProtoNode) // Remove one of the sharded directory blocks - if err := a.Block().Rm(ctx, path.IpfsPath(pbNode.Links()[0].Cid)); err != nil { + if err := a.Block().Rm(ctx, path.FromCid(pbNode.Links()[0].Cid)); err != nil { t.Fatal(err) } @@ -67,7 +67,12 @@ func TestPathUnixFSHAMTPartial(t *testing.T) { // The node will go out to the (non-existent) network looking for the missing block. Make sure we're erroring // because we exceeded the timeout on our query timeoutCtx, timeoutCancel := context.WithTimeout(ctx, time.Second*1) - _, err := a.ResolveNode(timeoutCtx, path.Join(r, k)) + newPath, err := path.Join(r, k) + if err != nil { + t.Fatal(err) + } + + _, err = a.ResolveNode(timeoutCtx, newPath) if err != nil { if timeoutCtx.Err() == nil { t.Fatal(err) diff --git a/core/coreapi/unixfs.go b/core/coreapi/unixfs.go index e1a607d7397..a7cac6a00d5 100644 --- a/core/coreapi/unixfs.go +++ b/core/coreapi/unixfs.go @@ -16,7 +16,6 @@ import ( bstore "github.com/ipfs/boxo/blockstore" coreiface "github.com/ipfs/boxo/coreiface" options "github.com/ipfs/boxo/coreiface/options" - path "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" filestore "github.com/ipfs/boxo/filestore" merkledag "github.com/ipfs/boxo/ipld/merkledag" @@ -25,6 +24,7 @@ import ( unixfile "github.com/ipfs/boxo/ipld/unixfs/file" uio "github.com/ipfs/boxo/ipld/unixfs/io" mfs "github.com/ipfs/boxo/mfs" + "github.com/ipfs/boxo/path" cid "github.com/ipfs/go-cid" cidutil "github.com/ipfs/go-cidutil" ipld "github.com/ipfs/go-ipld-format" @@ -58,13 +58,13 @@ func getOrCreateNilNode() (*core.IpfsNode, error) { // Add builds a merkledag node from a reader, adds it to the blockstore, // and returns the key representing that node. -func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options.UnixfsAddOption) (path.Resolved, error) { +func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options.UnixfsAddOption) (path.ImmutablePath, error) { ctx, span := tracing.Span(ctx, "CoreAPI.UnixfsAPI", "Add") defer span.End() settings, prefix, err := options.UnixfsAddOptions(opts...) if err != nil { - return nil, err + return path.ImmutablePath{}, err } span.SetAttributes( @@ -85,7 +85,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options cfg, err := api.repo.Config() if err != nil { - return nil, err + return path.ImmutablePath{}, err } // check if repo will exceed storage limit if added @@ -97,7 +97,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options //} if settings.NoCopy && !(cfg.Experimental.FilestoreEnabled || cfg.Experimental.UrlstoreEnabled) { - return nil, fmt.Errorf("either the filestore or the urlstore must be enabled to use nocopy, see: https://github.com/ipfs/kubo/blob/master/docs/experimental-features.md#ipfs-filestore") + return path.ImmutablePath{}, fmt.Errorf("either the filestore or the urlstore must be enabled to use nocopy, see: https://github.com/ipfs/kubo/blob/master/docs/experimental-features.md#ipfs-filestore") } addblockstore := api.blockstore @@ -110,7 +110,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options if settings.OnlyHash { node, err := getOrCreateNilNode() if err != nil { - return nil, err + return path.ImmutablePath{}, err } addblockstore = node.Blockstore exch = node.Exchange @@ -144,7 +144,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options fileAdder, err := coreunix.NewAdder(ctx, pinning, addblockstore, syncDserv) if err != nil { - return nil, err + return path.ImmutablePath{}, err } fileAdder.Chunker = settings.Chunker @@ -164,7 +164,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options case options.TrickleLayout: fileAdder.Trickle = true default: - return nil, fmt.Errorf("unknown layout: %d", settings.Layout) + return path.ImmutablePath{}, fmt.Errorf("unknown layout: %d", settings.Layout) } if settings.Inline { @@ -180,11 +180,11 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options // Use the same prefix for the "empty" MFS root as for the file adder. err := emptyDirNode.SetCidBuilder(fileAdder.CidBuilder) if err != nil { - return nil, err + return path.ImmutablePath{}, err } mr, err := mfs.NewRoot(ctx, md, emptyDirNode, nil) if err != nil { - return nil, err + return path.ImmutablePath{}, err } fileAdder.SetMfsRoot(mr) @@ -192,16 +192,16 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options nd, err := fileAdder.AddAllAndPin(ctx, files) if err != nil { - return nil, err + return path.ImmutablePath{}, err } if !settings.OnlyHash { if err := api.provider.Provide(nd.Cid()); err != nil { - return nil, err + return path.ImmutablePath{}, err } } - return path.IpfsPath(nd.Cid()), nil + return path.FromCid(nd.Cid()), nil } func (api *UnixfsAPI) Get(ctx context.Context, p path.Path) (files.Node, error) { diff --git a/core/corehttp/commands.go b/core/corehttp/commands.go index 53041e86bc5..804b70a7e2c 100644 --- a/core/corehttp/commands.go +++ b/core/corehttp/commands.go @@ -9,7 +9,6 @@ import ( "strconv" "strings" - path "github.com/ipfs/boxo/path" cmds "github.com/ipfs/go-ipfs-cmds" cmdsHttp "github.com/ipfs/go-ipfs-cmds/http" version "github.com/ipfs/kubo" @@ -171,7 +170,7 @@ func CheckVersionOption() ServeOption { parent.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, APIPath) { cmdqry := r.URL.Path[len(APIPath):] - pth := path.SplitList(cmdqry) + pth := strings.Split(cmdqry, "/") // backwards compatibility to previous version check if len(pth) >= 2 && pth[1] != "version" { diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go index 67da588cab6..3e0380d5a3c 100644 --- a/core/corehttp/gateway.go +++ b/core/corehttp/gateway.go @@ -7,14 +7,15 @@ import ( "io" "net" "net/http" + "time" "github.com/ipfs/boxo/blockservice" iface "github.com/ipfs/boxo/coreiface" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/exchange/offline" "github.com/ipfs/boxo/files" "github.com/ipfs/boxo/gateway" "github.com/ipfs/boxo/namesys" + "github.com/ipfs/boxo/path" offlineroute "github.com/ipfs/boxo/routing/offline" "github.com/ipfs/go-cid" version "github.com/ipfs/kubo" @@ -80,7 +81,11 @@ func Libp2pGatewayOption() ServeOption { return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) { bserv := blockservice.New(n.Blocks.Blockstore(), offline.Exchange(n.Blocks.Blockstore())) - backend, err := gateway.NewBlocksBackend(bserv) + backend, err := gateway.NewBlocksBackend(bserv, + // GatewayOverLibp2p only returns things that are in local blockstore + // (same as Gateway.NoFetch=true), we have to pass offline path resolver + gateway.WithResolver(n.OfflineUnixFSPathResolver), + ) if err != nil { return nil, err } @@ -110,6 +115,8 @@ func newGatewayBackend(n *core.IpfsNode) (gateway.IPFSBackend, error) { bserv := n.Blocks var vsRouting routing.ValueStore = n.Routing nsys := n.Namesys + pathResolver := n.UnixFSPathResolver + if cfg.Gateway.NoFetch { bserv = blockservice.New(bserv.Blockstore(), offline.Exchange(bserv.Blockstore())) @@ -129,9 +136,17 @@ func newGatewayBackend(n *core.IpfsNode) (gateway.IPFSBackend, error) { if err != nil { return nil, fmt.Errorf("error constructing namesys: %w", err) } + + // Gateway.NoFetch=true requires offline path resolver + // to avoid fetching missing blocks during path traversal + pathResolver = n.OfflineUnixFSPathResolver } - backend, err := gateway.NewBlocksBackend(bserv, gateway.WithValueStore(vsRouting), gateway.WithNameSystem(nsys)) + backend, err := gateway.NewBlocksBackend(bserv, + gateway.WithValueStore(vsRouting), + gateway.WithNameSystem(nsys), + gateway.WithResolver(pathResolver), + ) if err != nil { return nil, err } @@ -149,37 +164,37 @@ func offlineErrWrap(err error) error { return err } -func (o *offlineGatewayErrWrapper) Get(ctx context.Context, path gateway.ImmutablePath, ranges ...gateway.ByteRange) (gateway.ContentPathMetadata, *gateway.GetResponse, error) { +func (o *offlineGatewayErrWrapper) Get(ctx context.Context, path path.ImmutablePath, ranges ...gateway.ByteRange) (gateway.ContentPathMetadata, *gateway.GetResponse, error) { md, n, err := o.gwimpl.Get(ctx, path, ranges...) err = offlineErrWrap(err) return md, n, err } -func (o *offlineGatewayErrWrapper) GetAll(ctx context.Context, path gateway.ImmutablePath) (gateway.ContentPathMetadata, files.Node, error) { +func (o *offlineGatewayErrWrapper) GetAll(ctx context.Context, path path.ImmutablePath) (gateway.ContentPathMetadata, files.Node, error) { md, n, err := o.gwimpl.GetAll(ctx, path) err = offlineErrWrap(err) return md, n, err } -func (o *offlineGatewayErrWrapper) GetBlock(ctx context.Context, path gateway.ImmutablePath) (gateway.ContentPathMetadata, files.File, error) { +func (o *offlineGatewayErrWrapper) GetBlock(ctx context.Context, path path.ImmutablePath) (gateway.ContentPathMetadata, files.File, error) { md, n, err := o.gwimpl.GetBlock(ctx, path) err = offlineErrWrap(err) return md, n, err } -func (o *offlineGatewayErrWrapper) Head(ctx context.Context, path gateway.ImmutablePath) (gateway.ContentPathMetadata, files.Node, error) { +func (o *offlineGatewayErrWrapper) Head(ctx context.Context, path path.ImmutablePath) (gateway.ContentPathMetadata, *gateway.HeadResponse, error) { md, n, err := o.gwimpl.Head(ctx, path) err = offlineErrWrap(err) return md, n, err } -func (o *offlineGatewayErrWrapper) ResolvePath(ctx context.Context, path gateway.ImmutablePath) (gateway.ContentPathMetadata, error) { +func (o *offlineGatewayErrWrapper) ResolvePath(ctx context.Context, path path.ImmutablePath) (gateway.ContentPathMetadata, error) { md, err := o.gwimpl.ResolvePath(ctx, path) err = offlineErrWrap(err) return md, err } -func (o *offlineGatewayErrWrapper) GetCAR(ctx context.Context, path gateway.ImmutablePath, params gateway.CarParams) (gateway.ContentPathMetadata, io.ReadCloser, error) { +func (o *offlineGatewayErrWrapper) GetCAR(ctx context.Context, path path.ImmutablePath, params gateway.CarParams) (gateway.ContentPathMetadata, io.ReadCloser, error) { md, data, err := o.gwimpl.GetCAR(ctx, path, params) err = offlineErrWrap(err) return md, data, err @@ -195,10 +210,10 @@ func (o *offlineGatewayErrWrapper) GetIPNSRecord(ctx context.Context, c cid.Cid) return rec, err } -func (o *offlineGatewayErrWrapper) ResolveMutable(ctx context.Context, path path.Path) (gateway.ImmutablePath, error) { - imPath, err := o.gwimpl.ResolveMutable(ctx, path) +func (o *offlineGatewayErrWrapper) ResolveMutable(ctx context.Context, path path.Path) (path.ImmutablePath, time.Duration, time.Time, error) { + imPath, ttl, lastMod, err := o.gwimpl.ResolveMutable(ctx, path) err = offlineErrWrap(err) - return imPath, err + return imPath, ttl, lastMod, err } func (o *offlineGatewayErrWrapper) GetDNSLinkRecord(ctx context.Context, s string) (path.Path, error) { diff --git a/core/corehttp/gateway_test.go b/core/corehttp/gateway_test.go index b3acda31ce2..41a1c582179 100644 --- a/core/corehttp/gateway_test.go +++ b/core/corehttp/gateway_test.go @@ -17,7 +17,6 @@ import ( "github.com/stretchr/testify/assert" iface "github.com/ipfs/boxo/coreiface" - nsopts "github.com/ipfs/boxo/coreiface/options/namesys" "github.com/ipfs/boxo/path" "github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-datastore/sync" @@ -27,41 +26,47 @@ import ( type mockNamesys map[string]path.Path -func (m mockNamesys) Resolve(ctx context.Context, name string, opts ...nsopts.ResolveOpt) (value path.Path, err error) { - cfg := nsopts.DefaultResolveOpts() +func (m mockNamesys) Resolve(ctx context.Context, p path.Path, opts ...namesys.ResolveOption) (namesys.Result, error) { + cfg := namesys.DefaultResolveOptions() for _, o := range opts { o(&cfg) } depth := cfg.Depth - if depth == nsopts.UnlimitedDepth { + if depth == namesys.UnlimitedDepth { // max uint depth = ^uint(0) } + var ( + value path.Path + ) + name := path.SegmentsToString(p.Segments()[:2]...) for strings.HasPrefix(name, "/ipns/") { if depth == 0 { - return value, namesys.ErrResolveRecursion + return namesys.Result{Path: value}, namesys.ErrResolveRecursion } depth-- - var ok bool - value, ok = m[name] + v, ok := m[name] if !ok { - return "", namesys.ErrResolveFailed + return namesys.Result{}, namesys.ErrResolveFailed } + value = v name = value.String() } - return value, nil + + value, err := path.Join(value, p.Segments()[2:]...) + return namesys.Result{Path: value}, err } -func (m mockNamesys) ResolveAsync(ctx context.Context, name string, opts ...nsopts.ResolveOpt) <-chan namesys.Result { - out := make(chan namesys.Result, 1) - v, err := m.Resolve(ctx, name, opts...) - out <- namesys.Result{Path: v, Err: err} +func (m mockNamesys) ResolveAsync(ctx context.Context, p path.Path, opts ...namesys.ResolveOption) <-chan namesys.AsyncResult { + out := make(chan namesys.AsyncResult, 1) + res, err := m.Resolve(ctx, p, opts...) + out <- namesys.AsyncResult{Path: res.Path, TTL: res.TTL, LastMod: res.LastMod, Err: err} close(out) return out } -func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Path, opts ...nsopts.PublishOption) error { +func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Path, opts ...namesys.PublishOption) error { return errors.New("not implemented for mockNamesys") } diff --git a/core/corehttp/routing.go b/core/corehttp/routing.go index e648afb4ef4..88d9de88664 100644 --- a/core/corehttp/routing.go +++ b/core/corehttp/routing.go @@ -42,7 +42,7 @@ func (r *contentRouter) ProvideBitswap(ctx context.Context, req *server.BitswapW return 0, routing.ErrNotSupported } -func (r *contentRouter) FindPeers(ctx context.Context, pid peer.ID, limit int) (iter.ResultIter[types.Record], error) { +func (r *contentRouter) FindPeers(ctx context.Context, pid peer.ID, limit int) (iter.ResultIter[*types.PeerRecord], error) { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -60,7 +60,7 @@ func (r *contentRouter) FindPeers(ctx context.Context, pid peer.ID, limit int) ( rec.Addrs = append(rec.Addrs, types.Multiaddr{Multiaddr: addr}) } - return iter.ToResultIter[types.Record](iter.FromSlice[types.Record]([]types.Record{rec})), nil + return iter.ToResultIter[*types.PeerRecord](iter.FromSlice[*types.PeerRecord]([]*types.PeerRecord{rec})), nil } func (r *contentRouter) GetIPNS(ctx context.Context, name ipns.Name) (*ipns.Record, error) { diff --git a/core/coreunix/add.go b/core/coreunix/add.go index 31a867b037d..123c9fe652b 100644 --- a/core/coreunix/add.go +++ b/core/coreunix/add.go @@ -11,7 +11,6 @@ import ( bstore "github.com/ipfs/boxo/blockstore" chunker "github.com/ipfs/boxo/chunker" coreiface "github.com/ipfs/boxo/coreiface" - "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" posinfo "github.com/ipfs/boxo/filestore/posinfo" dag "github.com/ipfs/boxo/ipld/merkledag" @@ -20,6 +19,7 @@ import ( ihelper "github.com/ipfs/boxo/ipld/unixfs/importer/helpers" "github.com/ipfs/boxo/ipld/unixfs/importer/trickle" "github.com/ipfs/boxo/mfs" + "github.com/ipfs/boxo/path" pin "github.com/ipfs/boxo/pinning/pinner" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" @@ -506,7 +506,7 @@ func getOutput(dagnode ipld.Node) (*coreiface.AddEvent, error) { } output := &coreiface.AddEvent{ - Path: path.IpfsPath(c), + Path: path.FromCid(c), Size: strconv.FormatUint(s, 10), } diff --git a/core/coreunix/add_test.go b/core/coreunix/add_test.go index be6f98ed7db..a09fd5d2bc9 100644 --- a/core/coreunix/add_test.go +++ b/core/coreunix/add_test.go @@ -133,7 +133,7 @@ func TestAddMultipleGCLive(t *testing.T) { } for o := range out { - if _, ok := removedHashes[o.(*coreiface.AddEvent).Path.Cid().String()]; ok { + if _, ok := removedHashes[o.(*coreiface.AddEvent).Path.RootCid().String()]; ok { t.Fatal("gc'ed a hash we just added") } } @@ -187,7 +187,7 @@ func TestAddGCLive(t *testing.T) { addedHashes := make(map[string]struct{}) select { case o := <-out: - addedHashes[o.(*coreiface.AddEvent).Path.Cid().String()] = struct{}{} + addedHashes[o.(*coreiface.AddEvent).Path.RootCid().String()] = struct{}{} case <-addDone: t.Fatal("add shouldn't complete yet") } @@ -217,7 +217,7 @@ func TestAddGCLive(t *testing.T) { // receive next object from adder o := <-out - addedHashes[o.(*coreiface.AddEvent).Path.Cid().String()] = struct{}{} + addedHashes[o.(*coreiface.AddEvent).Path.RootCid().String()] = struct{}{} <-gcstarted @@ -233,7 +233,7 @@ func TestAddGCLive(t *testing.T) { var last cid.Cid for a := range out { // wait for it to finish - c, err := cid.Decode(a.(*coreiface.AddEvent).Path.Cid().String()) + c, err := cid.Decode(a.(*coreiface.AddEvent).Path.RootCid().String()) if err != nil { t.Fatal(err) } diff --git a/core/node/core.go b/core/node/core.go index d2d2c63d749..9a2035a4c8c 100644 --- a/core/node/core.go +++ b/core/node/core.go @@ -7,6 +7,7 @@ import ( "github.com/ipfs/boxo/blockservice" blockstore "github.com/ipfs/boxo/blockstore" exchange "github.com/ipfs/boxo/exchange" + offline "github.com/ipfs/boxo/exchange/offline" "github.com/ipfs/boxo/fetcher" bsfetcher "github.com/ipfs/boxo/fetcher/impl/blockservice" "github.com/ipfs/boxo/filestore" @@ -21,9 +22,6 @@ import ( format "github.com/ipfs/go-ipld-format" "github.com/ipfs/go-unixfsnode" dagpb "github.com/ipld/go-codec-dagpb" - "github.com/ipld/go-ipld-prime" - basicnode "github.com/ipld/go-ipld-prime/node/basic" - "github.com/ipld/go-ipld-prime/schema" "go.uber.org/fx" "github.com/ipfs/kubo/core/node/helpers" @@ -87,43 +85,58 @@ func (s *syncDagService) Session(ctx context.Context) format.NodeGetter { // FetchersOut allows injection of fetchers. type FetchersOut struct { fx.Out - IPLDFetcher fetcher.Factory `name:"ipldFetcher"` - UnixfsFetcher fetcher.Factory `name:"unixfsFetcher"` + IPLDFetcher fetcher.Factory `name:"ipldFetcher"` + UnixfsFetcher fetcher.Factory `name:"unixfsFetcher"` + OfflineIPLDFetcher fetcher.Factory `name:"offlineIpldFetcher"` + OfflineUnixfsFetcher fetcher.Factory `name:"offlineUnixfsFetcher"` } // FetchersIn allows using fetchers for other dependencies. type FetchersIn struct { fx.In - IPLDFetcher fetcher.Factory `name:"ipldFetcher"` - UnixfsFetcher fetcher.Factory `name:"unixfsFetcher"` + IPLDFetcher fetcher.Factory `name:"ipldFetcher"` + UnixfsFetcher fetcher.Factory `name:"unixfsFetcher"` + OfflineIPLDFetcher fetcher.Factory `name:"offlineIpldFetcher"` + OfflineUnixfsFetcher fetcher.Factory `name:"offlineUnixfsFetcher"` } // FetcherConfig returns a fetcher config that can build new fetcher instances func FetcherConfig(bs blockservice.BlockService) FetchersOut { ipldFetcher := bsfetcher.NewFetcherConfig(bs) - ipldFetcher.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 - }) - + ipldFetcher.PrototypeChooser = dagpb.AddSupportToChooser(bsfetcher.DefaultPrototypeChooser) unixFSFetcher := ipldFetcher.WithReifier(unixfsnode.Reify) - return FetchersOut{IPLDFetcher: ipldFetcher, UnixfsFetcher: unixFSFetcher} + + // Construct offline versions which we can safely use in contexts where + // path resolution should not fetch new blocks via exchange. + offlineBs := blockservice.New(bs.Blockstore(), offline.Exchange(bs.Blockstore())) + offlineIpldFetcher := bsfetcher.NewFetcherConfig(offlineBs) + offlineIpldFetcher.PrototypeChooser = dagpb.AddSupportToChooser(bsfetcher.DefaultPrototypeChooser) + offlineUnixFSFetcher := offlineIpldFetcher.WithReifier(unixfsnode.Reify) + + return FetchersOut{ + IPLDFetcher: ipldFetcher, + UnixfsFetcher: unixFSFetcher, + OfflineIPLDFetcher: offlineIpldFetcher, + OfflineUnixfsFetcher: offlineUnixFSFetcher, + } } // PathResolversOut allows injection of path resolvers type PathResolversOut struct { fx.Out - IPLDPathResolver pathresolver.Resolver `name:"ipldPathResolver"` - UnixFSPathResolver pathresolver.Resolver `name:"unixFSPathResolver"` + IPLDPathResolver pathresolver.Resolver `name:"ipldPathResolver"` + UnixFSPathResolver pathresolver.Resolver `name:"unixFSPathResolver"` + OfflineIPLDPathResolver pathresolver.Resolver `name:"offlineIpldPathResolver"` + OfflineUnixFSPathResolver pathresolver.Resolver `name:"offlineUnixFSPathResolver"` } // PathResolverConfig creates path resolvers with the given fetchers. func PathResolverConfig(fetchers FetchersIn) PathResolversOut { return PathResolversOut{ - IPLDPathResolver: pathresolver.NewBasicResolver(fetchers.IPLDFetcher), - UnixFSPathResolver: pathresolver.NewBasicResolver(fetchers.UnixfsFetcher), + IPLDPathResolver: pathresolver.NewBasicResolver(fetchers.IPLDFetcher), + UnixFSPathResolver: pathresolver.NewBasicResolver(fetchers.UnixfsFetcher), + OfflineIPLDPathResolver: pathresolver.NewBasicResolver(fetchers.OfflineIPLDFetcher), + OfflineUnixFSPathResolver: pathresolver.NewBasicResolver(fetchers.OfflineUnixfsFetcher), } } diff --git a/core/node/peering.go b/core/node/peering.go index eba165ef984..d6b56383526 100644 --- a/core/node/peering.go +++ b/core/node/peering.go @@ -3,7 +3,7 @@ package node import ( "context" - "github.com/ipfs/kubo/peering" + "github.com/ipfs/boxo/peering" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" "go.uber.org/fx" @@ -18,7 +18,8 @@ func Peering(lc fx.Lifecycle, host host.Host) *peering.PeeringService { return ps.Start() }, OnStop: func(context.Context) error { - return ps.Stop() + ps.Stop() + return nil }, }) return ps diff --git a/docs/changelogs/v0.24.md b/docs/changelogs/v0.24.md new file mode 100644 index 00000000000..29d88d9cbd0 --- /dev/null +++ b/docs/changelogs/v0.24.md @@ -0,0 +1,73 @@ +# Kubo changelog v0.24 + +- [v0.24.0](#v0240) + +## v0.24.0 + +- [Overview](#overview) +- [🔦 Highlights](#-highlights) + - [Support for content blocking](#support-for-content-blocking) + - [Gateway: the root of the CARs are no longer meaningful](#gateway-the-root-of-the-cars-are-no-longer-meaningful) + - [IPNS: improved publishing defaults](#ipns-improved-publishing-defaults) + - [IPNS: record TTL is used for caching](#ipns-record-ttl-is-used-for-caching) +- [📝 Changelog](#-changelog) +- [👨‍👩‍👧‍👦 Contributors](#-contributors) + +### Overview + +### 🔦 Highlights + +#### Support for content blocking + +This Kubo release ships with built-in content-blocking subsystem [announced earlier this year](https://blog.ipfs.tech/2023-content-blocking-for-the-ipfs-stack/). +Content blocking is an opt-in decision made by the operator of `ipfs daemon`. +The official build does not ship with any denylists. + +Learn more at [`/docs/content-blocking.md`](https://github.com/ipfs/kubo/blob/master/docs/content-blocking.md) + +#### Gateway: the root of the CARs are no longer meaningful + +When requesting a CAR from the gateway, the root of the CAR might no longer be +meaningful. By default, the CAR root will be the last resolvable segment of the +path. However, in situations where the path cannot be resolved, such as when +the path does not exist, a CAR will be sent with a root of `bafkqaaa` (empty CID). +This CAR will contain all blocks necessary to validate that the path does not exist. + +#### IPNS: improved publishing defaults + +This release changes the default values used when publishing IPNS record +via `ipfs name publish` command: + +- Default `--lifetime` increased from `24h` to `48h` to take full advantage of + the increased expiration window of Amino DHT + ([go-libp2p-kad-dht#793](https://github.com/libp2p/go-libp2p-kad-dht/pull/793)) +- Default `--ttl` increased from `1m` to `1h` to improve website caching and follow + saner defaults present in similar systems like DNS + ([specs#371](https://github.com/ipfs/specs/pull/371)) + +This change only impacts the implicit defaults, when mentioned parameters are omitted +during publishing. Users are free to override the default if different value +makes more sense for their use case. + +#### IPNS: record TTL is used for caching + +In this release, we've made significant improvements to IPNS caching. + +Previously, the TTL value in IPNS records was not utilized, and the +`boxo/namesys` library maintained a static one-minute resolution cache. + +With this update, IPNS publishers gain more control over how long a valid IPNS +record remains cached before checking an upstream routing system, such as Amino +DHT, for updates. The TTL value in the IPNS record now serves as a hint for: + +- `boxo/namesys`: the internal cache, determining how long the IPNS resolution + result is cached before asking upsteam routing systems for updates. +- `boxo/gateway`: the `Cache-Control` HTTP header in responses to requests made + for `/ipns/name` content paths. + +These changes make it easier for rarely updated IPNS-hosted websites to be +cached more efficiently and load faster in browser contexts. + +### 📝 Changelog + +### 👨‍👩‍👧‍👦 Contributors diff --git a/docs/content-blocking.md b/docs/content-blocking.md new file mode 100644 index 00000000000..ebc84bba3ea --- /dev/null +++ b/docs/content-blocking.md @@ -0,0 +1,73 @@ +

+
+ content blocking logo +
+ Content Blocking in Kubo +
+

+ +Kubo ships with built-in support for denylist format from [IPIP-383](https://github.com/ipfs/specs/pull/383). + +## Default behavior + +Official Kubo build does not ship with any denylists enabled by default. + +Content blocking is an opt-in decision made by the operator of `ipfs daemon`. + +## How to enable blocking + +Place a `*.deny` file in one of directories: + +- `$IPFS_PATH/denylists/` (`$HOME/.ipfs/denylists/` if `IPFS_PATH` is not set) +- `$XDG_CONFIG_HOME/ipfs/denylists/` (`$HOME/.config/ipfs/denylists/` if `XDG_CONFIG_HOME` is not set) +- `/etc/ipfs/denylists/` (global) + +Files need to be present before starting the `ipfs daemon` in order to be watched for updates. + +If a new denylist file is added, `ipfs daemon` needs to be restarted. + +CLI and Gateway users will receive errors in response to request impacted by a blocklist: + +``` +Error: /ipfs/QmQvjk82hPkSaZsyJ8vNER5cmzKW7HyGX5XVusK7EAenCN is blocked and cannot be provided +``` + +End user is not informed about the exact reason, see [How to +debug](#how-to-debug) if you need to find out which line of which denylist +caused the request to be blocked. + +## Denylist file format + +[NOpfs](https://github.com/ipfs-shipyard/nopfs) supports the format from [IPIP-383](https://github.com/ipfs/specs/pull/383). + +Clear-text rules are simple: just put content paths to block, one per line. +Paths with unicode and whitespace need to be percend-encoded: + +``` +/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR +/ipfs/bafybeihfg3d7rdltd43u3tfvncx7n5loqofbsobojcadtmokrljfthuc7y/927%20-%20Standards/927%20-%20Standards.png +``` + +Sensitive content paths can be double-hashed to block without revealing them. +Double-hashed list example: https://badbits.dwebops.pub/badbits.deny + +See [IPIP-383](https://github.com/ipfs/specs/pull/383) for detailed format specification and more examples. + +## How to suspend blocking without removing denylists + +Set `IPFS_CONTENT_BLOCKING_DISABLE` environment variable to `true` and restart the daemon. + + +## How to debug + +Debug logging of `nopfs` subsystem can be enabled with `GOLOG_LOG_LEVEL="nopfs=debug"` + +All block events are logged as warnings on a separate level named `nopfs-blocks`. + +To only log requests for blocked content set `GOLOG_LOG_LEVEL="nopfs-blocks=warn"`: + +``` +WARN (...) QmRFniDxwxoG2n4AcnGhRdjqDjCM5YeUcBE75K8WXmioH3: blocked (test.deny:9) +``` + + diff --git a/docs/environment-variables.md b/docs/environment-variables.md index 4113be09b82..f0f6b3f183a 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -131,6 +131,12 @@ The above will replace implicit HTTP routers with single one, allowing for inspection/debug of HTTP requests sent by Kubo via `while true ; do nc -l 7423; done` or more advanced tools like [mitmproxy](https://docs.mitmproxy.org/stable/#mitmproxy). + +## `IPFS_CONTENT_BLOCKING_DISABLE` + +Disables the content-blocking subsystem. No denylists will be watched and no +content will be blocked. + ## `LIBP2P_TCP_REUSEPORT` Kubo tries to reuse the same source port for all connections to improve NAT diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod index 80f8172c488..b2b90bf3bd3 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.20 replace github.com/ipfs/kubo => ./../../.. require ( - github.com/ipfs/boxo v0.13.1 + github.com/ipfs/boxo v0.14.0 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000 github.com/libp2p/go-libp2p v0.31.0 github.com/multiformats/go-multiaddr v0.11.0 @@ -40,6 +40,7 @@ require ( github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -51,18 +52,20 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/huin/goupnp v1.2.0 // indirect + github.com/ipfs-shipyard/nopfs v0.0.12-0.20231027223058-cde3b5ba964c // indirect + github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect - github.com/ipfs/go-block-format v0.1.2 // indirect + github.com/ipfs/go-block-format v0.2.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-cidutil v0.1.0 // indirect github.com/ipfs/go-datastore v0.6.0 // indirect @@ -80,7 +83,7 @@ require ( github.com/ipfs/go-ipfs-redirects-file v0.1.1 // indirect github.com/ipfs/go-ipfs-util v0.0.3 // indirect github.com/ipfs/go-ipld-cbor v0.0.6 // indirect - github.com/ipfs/go-ipld-format v0.5.0 // indirect + github.com/ipfs/go-ipld-format v0.6.0 // indirect github.com/ipfs/go-ipld-git v0.1.1 // indirect github.com/ipfs/go-ipld-legacy v0.2.1 // indirect github.com/ipfs/go-log v1.0.5 // indirect @@ -142,10 +145,10 @@ require ( github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/polydawn/refmt v0.89.0 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.3.3 // indirect github.com/quic-go/quic-go v0.38.1 // indirect @@ -162,7 +165,7 @@ require ( github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect + go.opentelemetry.io/otel v1.17.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect @@ -170,29 +173,30 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 // indirect go.opentelemetry.io/otel/exporters/zipkin v1.14.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect + go.opentelemetry.io/otel/metric v1.17.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect + go.opentelemetry.io/otel/trace v1.17.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.20.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.25.0 // indirect + go.uber.org/zap v1.26.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect - golang.org/x/crypto v0.12.0 // indirect - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.14.0 // indirect + golang.org/x/net v0.15.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect - golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.13.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gonum.org/v1/gonum v0.13.0 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect google.golang.org/grpc v1.55.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum index feaef33b5c7..ba1c192a227 100644 --- a/docs/examples/kubo-as-a-library/go.sum +++ b/docs/examples/kubo-as-a-library/go.sum @@ -163,6 +163,7 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q= github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -261,8 +262,8 @@ github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0Z github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -290,24 +291,28 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= -github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/ipfs-shipyard/nopfs v0.0.12-0.20231027223058-cde3b5ba964c h1:17FO7HnKiFhO7iadu3zCgII+EblpdRmJt5qg9FqQo8Y= +github.com/ipfs-shipyard/nopfs v0.0.12-0.20231027223058-cde3b5ba964c/go.mod h1:1oj4+g/mN6JRuZiXHt5iFRG02e62wp5AKcB3gdgknbk= +github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7UynTbtdlt+w08ggb1UGLGaGjp1mMaZhoTZSctpn5Ak= +github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI= 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/boxo v0.13.1 h1:nQ5oQzcMZR3oL41REJDcTbrvDvuZh3J9ckc9+ILeRQI= -github.com/ipfs/boxo v0.13.1/go.mod h1:btrtHy0lmO1ODMECbbEY1pxNtrLilvKSYLoGQt1yYCk= +github.com/ipfs/boxo v0.14.0 h1:gwSGW3xqUbtUOdn71oqBknpBFKpQm352g3I+RkebrX0= +github.com/ipfs/boxo v0.14.0/go.mod h1:pu8HsZvuyYeYJsqtLDCoYSvy8rHj6vI3dlh8P0f83Zs= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= -github.com/ipfs/go-block-format v0.1.2 h1:GAjkfhVx1f4YTODS6Esrj1wt2HhrtwTnhEr+DyPUaJo= -github.com/ipfs/go-block-format v0.1.2/go.mod h1:mACVcrxarQKstUU3Yf/RdwbC4DzPV6++rO2a3d+a/KE= +github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= +github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= github.com/ipfs/go-blockservice v0.5.0 h1:B2mwhhhVQl2ntW2EIpaWPwSCxSuqr5fFA93Ms4bYLEY= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -365,8 +370,8 @@ github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn github.com/ipfs/go-ipld-cbor v0.0.6 h1:pYuWHyvSpIsOOLw4Jy7NbBkCyzLDcl64Bf/LZW7eBQ0= github.com/ipfs/go-ipld-cbor v0.0.6/go.mod h1:ssdxxaLJPXH7OjF5V4NSjBbcfh+evoR4ukuru0oPXMA= github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= -github.com/ipfs/go-ipld-format v0.5.0 h1:WyEle9K96MSrvr47zZHKKcDxJ/vlpET6PSiQsAFO+Ds= -github.com/ipfs/go-ipld-format v0.5.0/go.mod h1:ImdZqJQaEouMjCvqCe0ORUS+uoBmf7Hf+EO/jh+nk3M= +github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= +github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg= github.com/ipfs/go-ipld-git v0.1.1 h1:TWGnZjS0htmEmlMFEkA3ogrNCqWjIxwr16x1OsdhG+Y= github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYDpKUkJubI= github.com/ipfs/go-ipld-legacy v0.2.1 h1:mDFtrBpmU7b//LzLSypVrXsD8QxkEWxu5qVxN99/+tk= @@ -624,18 +629,18 @@ github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXx github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= @@ -771,8 +776,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= +go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= +go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= go.opentelemetry.io/otel/exporters/jaeger v1.14.0 h1:CjbUNd4iN2hHmWekmOqZ+zSCU+dzZppG8XsV+A3oc8Q= go.opentelemetry.io/otel/exporters/jaeger v1.14.0/go.mod h1:4Ay9kk5vELRrbg5z4cpP9EtmQRFap2Wb0woPG4lujZA= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= @@ -787,12 +792,12 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 h1:sEL90JjOO/4yhqu go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0/go.mod h1:oCslUcizYdpKYyS9e8srZEqM6BB8fq41VJBjLAE6z1w= go.opentelemetry.io/otel/exporters/zipkin v1.14.0 h1:reEVE1upBF9tcujgvSqLJS0SrI7JQPaTKP4s4rymnSs= go.opentelemetry.io/otel/exporters/zipkin v1.14.0/go.mod h1:RcjvOAcvhzcufQP8aHmzRw1gE9g/VEZufDdo2w+s4sk= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc= +go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= +go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -817,8 +822,8 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= @@ -840,8 +845,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 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= @@ -852,8 +857,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-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 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= @@ -921,8 +926,8 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 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= @@ -1001,10 +1006,11 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.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= @@ -1018,8 +1024,8 @@ golang.org/x/text v0.3.5/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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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= @@ -1077,8 +1083,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/docs/examples/kubo-as-a-library/main.go b/docs/examples/kubo-as-a-library/main.go index 785973c5baa..b7764a20651 100644 --- a/docs/examples/kubo-as-a-library/main.go +++ b/docs/examples/kubo-as-a-library/main.go @@ -12,8 +12,8 @@ import ( "sync" icore "github.com/ipfs/boxo/coreiface" - icorepath "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" + "github.com/ipfs/boxo/path" ma "github.com/multiformats/go-multiaddr" "github.com/ipfs/kubo/config" @@ -320,11 +320,11 @@ func main() { } }() - exampleCIDStr := peerCidFile.Cid().String() + exampleCIDStr := peerCidFile.RootCid().String() fmt.Printf("Fetching a file from the network with CID %s\n", exampleCIDStr) outputPath := outputBasePath + exampleCIDStr - testCID := icorepath.New(exampleCIDStr) + testCID := path.FromCid(peerCidFile.RootCid()) rootNode, err := ipfsB.Unixfs().Get(ctx, testCID) if err != nil { diff --git a/docs/http-rpc-clients.md b/docs/http-rpc-clients.md index 0b4baa1b0d1..74094a4ca63 100644 --- a/docs/http-rpc-clients.md +++ b/docs/http-rpc-clients.md @@ -2,12 +2,6 @@ Kubo provides official HTTP RPC (`/api/v0`) clients for selected languages: -- [`js-kubo-rpc-client`](https://github.com/ipfs/js-kubo-rpc-client) - Official JS client for talking to Kubo RPC over HTTP -- [`go-ipfs-api`](https://github.com/ipfs/go-ipfs-api) - The go interface to ipfs's HTTP RPC - Follow https://github.com/ipfs/kubo/issues/9124 for coming changes. -- [`httpapi`](./client/rpc) (previously `go-ipfs-http-client`) - [`coreiface.CoreAPI`](https://pkg.go.dev/github.com/ipfs/boxo/coreiface#CoreAPI) implementation using HTTP RPC - -## Recommended clients - | Language | Package Name | Github Repository | |:--------:|:-------------------:|--------------------------------------------| | JS | kubo-rpc-client | https://github.com/ipfs/js-kubo-rpc-client | diff --git a/fuse/ipns/common.go b/fuse/ipns/common.go index db231fe4570..7306196c8c6 100644 --- a/fuse/ipns/common.go +++ b/fuse/ipns/common.go @@ -4,8 +4,8 @@ import ( "context" ft "github.com/ipfs/boxo/ipld/unixfs" - nsys "github.com/ipfs/boxo/namesys" - path "github.com/ipfs/boxo/path" + "github.com/ipfs/boxo/namesys" + "github.com/ipfs/boxo/path" "github.com/ipfs/kubo/core" ci "github.com/libp2p/go-libp2p/core/crypto" ) @@ -28,7 +28,7 @@ func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error { return err } - pub := nsys.NewIpnsPublisher(n.Routing, n.Repo.Datastore()) + pub := namesys.NewIPNSPublisher(n.Routing, n.Repo.Datastore()) return pub.Publish(ctx, key, path.FromCid(emptyDir.Cid())) } diff --git a/fuse/ipns/ipns_unix.go b/fuse/ipns/ipns_unix.go index 2cb25d33297..77cb8b18f78 100644 --- a/fuse/ipns/ipns_unix.go +++ b/fuse/ipns/ipns_unix.go @@ -14,9 +14,9 @@ import ( "strings" "syscall" - path "github.com/ipfs/boxo/coreiface/path" dag "github.com/ipfs/boxo/ipld/merkledag" ft "github.com/ipfs/boxo/ipld/unixfs" + "github.com/ipfs/boxo/path" fuse "bazil.org/fuse" fs "bazil.org/fuse/fs" @@ -86,7 +86,7 @@ type Root struct { func ipnsPubFunc(ipfs iface.CoreAPI, key iface.Key) mfs.PubFunc { return func(ctx context.Context, c cid.Cid) error { - _, err := ipfs.Name().Publish(ctx, path.IpfsPath(c), options.Name.Key(key.Name())) + _, err := ipfs.Name().Publish(ctx, path.FromCid(c), options.Name.Key(key.Name())) return err } } @@ -186,7 +186,7 @@ func (r *Root) Lookup(ctx context.Context, name string) (fs.Node, error) { return nil, syscall.Errno(syscall.ENOENT) } - if resolved.Namespace() != "ipfs" { + if resolved.Namespace() != path.IPFSNamespace { return nil, errors.New("invalid path from ipns record") } diff --git a/fuse/readonly/ipfs_test.go b/fuse/readonly/ipfs_test.go index bc6204abb6a..385ae1272c5 100644 --- a/fuse/readonly/ipfs_test.go +++ b/fuse/readonly/ipfs_test.go @@ -11,7 +11,7 @@ import ( "io" "math/rand" "os" - "path" + gopath "path" "strings" "sync" "testing" @@ -24,11 +24,11 @@ import ( fstest "bazil.org/fuse/fs/fstestutil" chunker "github.com/ipfs/boxo/chunker" - ipath "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" dag "github.com/ipfs/boxo/ipld/merkledag" importer "github.com/ipfs/boxo/ipld/unixfs/importer" uio "github.com/ipfs/boxo/ipld/unixfs/io" + "github.com/ipfs/boxo/path" u "github.com/ipfs/boxo/util" ipld "github.com/ipfs/go-ipld-format" ci "github.com/libp2p/go-libp2p-testing/ci" @@ -89,7 +89,7 @@ func TestIpfsBasicRead(t *testing.T) { fi, data := randObj(t, nd, 10000) k := fi.Cid() - fname := path.Join(mnt.Dir, k.String()) + fname := gopath.Join(mnt.Dir, k.String()) rbuf, err := os.ReadFile(fname) if err != nil { t.Fatal(err) @@ -116,7 +116,7 @@ func getPaths(t *testing.T, ipfs *core.IpfsNode, name string, n *dag.ProtoNode) t.Fatal(dag.ErrNotProtobuf) } - sub := getPaths(t, ipfs, path.Join(name, lnk.Name), childpb) + sub := getPaths(t, ipfs, gopath.Join(name, lnk.Name), childpb) out = append(out, sub...) } return out @@ -184,10 +184,14 @@ func TestIpfsStressRead(t *testing.T) { defer wg.Done() for i := 0; i < 2000; i++ { - item := ipath.New(paths[rand.Intn(len(paths))]) + item, err := path.NewPath(paths[rand.Intn(len(paths))]) + if err != nil { + errs <- err + continue + } relpath := strings.Replace(item.String(), item.Namespace(), "", 1) - fname := path.Join(mnt.Dir, relpath) + fname := gopath.Join(mnt.Dir, relpath) rbuf, err := os.ReadFile(fname) if err != nil { @@ -257,8 +261,8 @@ func TestIpfsBasicDirRead(t *testing.T) { t.Fatal(err) } - dirname := path.Join(mnt.Dir, d1nd.Cid().String()) - fname := path.Join(dirname, "actual") + dirname := gopath.Join(mnt.Dir, d1nd.Cid().String()) + fname := gopath.Join(dirname, "actual") rbuf, err := os.ReadFile(fname) if err != nil { t.Fatal(err) @@ -291,7 +295,7 @@ func TestFileSizeReporting(t *testing.T) { fi, data := randObj(t, nd, 10000) k := fi.Cid() - fname := path.Join(mnt.Dir, k.String()) + fname := gopath.Join(mnt.Dir, k.String()) finfo, err := os.Stat(fname) if err != nil { diff --git a/fuse/readonly/readonly_unix.go b/fuse/readonly/readonly_unix.go index e944f1b6e00..9dca9c1a9b2 100644 --- a/fuse/readonly/readonly_unix.go +++ b/fuse/readonly/readonly_unix.go @@ -16,7 +16,7 @@ import ( mdag "github.com/ipfs/boxo/ipld/merkledag" ft "github.com/ipfs/boxo/ipld/unixfs" uio "github.com/ipfs/boxo/ipld/unixfs/io" - path "github.com/ipfs/boxo/path" + "github.com/ipfs/boxo/path" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" logging "github.com/ipfs/go-log" @@ -62,13 +62,19 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) { return nil, syscall.Errno(syscall.ENOENT) } - p, err := path.ParsePath(name) + p, err := path.NewPath(name) if err != nil { log.Debugf("fuse failed to parse path: %q: %s", name, err) return nil, syscall.Errno(syscall.ENOENT) } - nd, ndLnk, err := s.Ipfs.UnixFSPathResolver.ResolvePath(ctx, p) + imPath, err := path.NewImmutablePath(p) + if err != nil { + log.Debugf("fuse failed to convert path: %q: %s", name, err) + return nil, syscall.Errno(syscall.ENOENT) + } + + nd, ndLnk, err := s.Ipfs.UnixFSPathResolver.ResolvePath(ctx, imPath) if err != nil { // todo: make this error more versatile. return nil, syscall.Errno(syscall.ENOENT) diff --git a/go.mod b/go.mod index 3dc7f6827e9..1acc57dae02 100644 --- a/go.mod +++ b/go.mod @@ -13,10 +13,12 @@ require ( github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302 github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 github.com/fsnotify/fsnotify v1.6.0 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/hashicorp/go-multierror v1.1.1 - github.com/ipfs/boxo v0.13.1 - github.com/ipfs/go-block-format v0.1.2 + github.com/ipfs-shipyard/nopfs v0.0.12-0.20231027223058-cde3b5ba964c + github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c + github.com/ipfs/boxo v0.14.0 + github.com/ipfs/go-block-format v0.2.0 github.com/ipfs/go-cid v0.4.1 github.com/ipfs/go-cidutil v0.1.0 github.com/ipfs/go-datastore v0.6.0 @@ -28,7 +30,7 @@ require ( github.com/ipfs/go-fs-lock v0.0.7 github.com/ipfs/go-graphsync v0.15.1 github.com/ipfs/go-ipfs-cmds v0.10.0 - github.com/ipfs/go-ipld-format v0.5.0 + github.com/ipfs/go-ipld-format v0.6.0 github.com/ipfs/go-ipld-git v0.1.1 github.com/ipfs/go-ipld-legacy v0.2.1 github.com/ipfs/go-log v1.0.5 @@ -65,7 +67,7 @@ require ( github.com/opentracing/opentracing-go v1.2.0 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.16.0 + github.com/prometheus/client_golang v1.17.0 github.com/stretchr/testify v1.8.4 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tidwall/gjson v1.14.4 @@ -75,18 +77,18 @@ require ( go.opencensus.io v0.24.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 go.opentelemetry.io/contrib/propagators/autoprop v0.42.0 - go.opentelemetry.io/otel v1.16.0 + go.opentelemetry.io/otel v1.17.0 go.opentelemetry.io/otel/sdk v1.16.0 - go.opentelemetry.io/otel/trace v1.16.0 + go.opentelemetry.io/otel/trace v1.17.0 go.uber.org/dig v1.17.0 go.uber.org/fx v1.20.0 go.uber.org/multierr v1.11.0 - go.uber.org/zap v1.25.0 - golang.org/x/crypto v0.12.0 - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 + go.uber.org/zap v1.26.0 + golang.org/x/crypto v0.14.0 + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/mod v0.12.0 golang.org/x/sync v0.3.0 - golang.org/x/sys v0.11.0 + golang.org/x/sys v0.13.0 google.golang.org/protobuf v1.31.0 ) @@ -131,7 +133,7 @@ require ( github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/huin/goupnp v1.2.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect @@ -186,9 +188,9 @@ require ( github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/polydawn/refmt v0.89.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/statsd_exporter v0.22.7 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.3.3 // indirect @@ -218,15 +220,15 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 // indirect go.opentelemetry.io/otel/exporters/zipkin v1.14.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect + go.opentelemetry.io/otel/metric v1.17.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.uber.org/atomic v1.11.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect - golang.org/x/net v0.14.0 // indirect + golang.org/x/net v0.15.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/term v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect - golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.13.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gonum.org/v1/gonum v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 9e06cc307d0..69ae8aff6fe 100644 --- a/go.sum +++ b/go.sum @@ -295,8 +295,8 @@ github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0Z github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -325,25 +325,29 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= -github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/ipfs-shipyard/nopfs v0.0.12-0.20231027223058-cde3b5ba964c h1:17FO7HnKiFhO7iadu3zCgII+EblpdRmJt5qg9FqQo8Y= +github.com/ipfs-shipyard/nopfs v0.0.12-0.20231027223058-cde3b5ba964c/go.mod h1:1oj4+g/mN6JRuZiXHt5iFRG02e62wp5AKcB3gdgknbk= +github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7UynTbtdlt+w08ggb1UGLGaGjp1mMaZhoTZSctpn5Ak= +github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI= 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/boxo v0.13.1 h1:nQ5oQzcMZR3oL41REJDcTbrvDvuZh3J9ckc9+ILeRQI= -github.com/ipfs/boxo v0.13.1/go.mod h1:btrtHy0lmO1ODMECbbEY1pxNtrLilvKSYLoGQt1yYCk= +github.com/ipfs/boxo v0.14.0 h1:gwSGW3xqUbtUOdn71oqBknpBFKpQm352g3I+RkebrX0= +github.com/ipfs/boxo v0.14.0/go.mod h1:pu8HsZvuyYeYJsqtLDCoYSvy8rHj6vI3dlh8P0f83Zs= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= -github.com/ipfs/go-block-format v0.1.2 h1:GAjkfhVx1f4YTODS6Esrj1wt2HhrtwTnhEr+DyPUaJo= -github.com/ipfs/go-block-format v0.1.2/go.mod h1:mACVcrxarQKstUU3Yf/RdwbC4DzPV6++rO2a3d+a/KE= +github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= +github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= github.com/ipfs/go-blockservice v0.5.0 h1:B2mwhhhVQl2ntW2EIpaWPwSCxSuqr5fFA93Ms4bYLEY= github.com/ipfs/go-blockservice v0.5.0/go.mod h1:W6brZ5k20AehbmERplmERn8o2Ni3ZZubvAxaIUeaT6w= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -405,8 +409,8 @@ github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn github.com/ipfs/go-ipld-cbor v0.0.6 h1:pYuWHyvSpIsOOLw4Jy7NbBkCyzLDcl64Bf/LZW7eBQ0= github.com/ipfs/go-ipld-cbor v0.0.6/go.mod h1:ssdxxaLJPXH7OjF5V4NSjBbcfh+evoR4ukuru0oPXMA= github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= -github.com/ipfs/go-ipld-format v0.5.0 h1:WyEle9K96MSrvr47zZHKKcDxJ/vlpET6PSiQsAFO+Ds= -github.com/ipfs/go-ipld-format v0.5.0/go.mod h1:ImdZqJQaEouMjCvqCe0ORUS+uoBmf7Hf+EO/jh+nk3M= +github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= +github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg= github.com/ipfs/go-ipld-git v0.1.1 h1:TWGnZjS0htmEmlMFEkA3ogrNCqWjIxwr16x1OsdhG+Y= github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYDpKUkJubI= github.com/ipfs/go-ipld-legacy v0.2.1 h1:mDFtrBpmU7b//LzLSypVrXsD8QxkEWxu5qVxN99/+tk= @@ -712,14 +716,14 @@ github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -738,8 +742,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= @@ -909,8 +913,8 @@ go.opentelemetry.io/contrib/propagators/jaeger v1.17.0 h1:Zbpbmwav32Ea5jSotpmkWE go.opentelemetry.io/contrib/propagators/jaeger v1.17.0/go.mod h1:tcTUAlmO8nuInPDSBVfG+CP6Mzjy5+gNV4mPxMbL0IA= go.opentelemetry.io/contrib/propagators/ot v1.17.0 h1:ufo2Vsz8l76eI47jFjuVyjyB3Ae2DmfiCV/o6Vc8ii0= go.opentelemetry.io/contrib/propagators/ot v1.17.0/go.mod h1:SbKPj5XGp8K/sGm05XblaIABgMgw2jDczP8gGeuaVLk= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= +go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= +go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= go.opentelemetry.io/otel/exporters/jaeger v1.14.0 h1:CjbUNd4iN2hHmWekmOqZ+zSCU+dzZppG8XsV+A3oc8Q= go.opentelemetry.io/otel/exporters/jaeger v1.14.0/go.mod h1:4Ay9kk5vELRrbg5z4cpP9EtmQRFap2Wb0woPG4lujZA= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= @@ -925,12 +929,12 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 h1:sEL90JjOO/4yhqu go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0/go.mod h1:oCslUcizYdpKYyS9e8srZEqM6BB8fq41VJBjLAE6z1w= go.opentelemetry.io/otel/exporters/zipkin v1.14.0 h1:reEVE1upBF9tcujgvSqLJS0SrI7JQPaTKP4s4rymnSs= go.opentelemetry.io/otel/exporters/zipkin v1.14.0/go.mod h1:RcjvOAcvhzcufQP8aHmzRw1gE9g/VEZufDdo2w+s4sk= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc= +go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= +go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -955,8 +959,8 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= @@ -978,8 +982,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 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= @@ -990,8 +994,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-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 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= @@ -1065,8 +1069,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 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= @@ -1164,14 +1168,14 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.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= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1181,8 +1185,8 @@ golang.org/x/text v0.3.5/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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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= @@ -1240,8 +1244,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/package-list.json b/package-list.json deleted file mode 100644 index 7dfc5648cf0..00000000000 --- a/package-list.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "columns": [ - "Name", - "CI/Travis", - "Coverage", - "Description" - ], - "rows": [ - "Libp2p", - ["libp2p/go-libp2p", "go-libp2p", "p2p networking library"], - ["libp2p/go-libp2p-pubsub", "go-libp2p-pubsub", "pubsub built on libp2p"], - ["libp2p/go-libp2p-kad-dht", "go-libp2p-kad-dht", "dht-backed router"], - ["libp2p/go-libp2p-pubsub-router", "go-libp2p-pubsub-router", "pubsub-backed router"], - - "Multiformats", - ["ipfs/go-cid", "go-cid", "CID implementation"], - ["multiformats/go-multiaddr", "go-multiaddr", "multiaddr implementation"], - ["multiformats/go-multihash", "go-multihash", "multihash implementation"], - ["multiformats/go-multibase", "go-multibase", "mulitbase implementation"], - - "Files", - ["ipfs/go-unixfs", "go-unixfs", "the core 'filesystem' logic"], - ["ipfs/go-mfs", "go-mfs", "a mutable filesystem editor for unixfs"], - ["ipfs/go-ipfs-posinfo", "go-ipfs-posinfo", "helper datatypes for the filestore"], - ["ipfs/go-ipfs-chunker", "go-ipfs-chunker", "file chunkers"], - - "Exchange", - ["ipfs/go-ipfs-exchange-interface", "go-ipfs-exchange-interface", "exchange service interface"], - ["ipfs/go-ipfs-exchange-offline", "go-ipfs-exchange-offline", "(dummy) offline implementation of the exchange service"], - ["ipfs/go-bitswap", "go-bitswap", "bitswap protocol implementation"], - ["ipfs/go-blockservice", "go-blockservice", "service that plugs a blockstore and an exchange together"], - - "Datastores", - ["ipfs/go-datastore", "go-datastore", "datastore interfaces, adapters, and basic implementations"], - ["ipfs/go-ipfs-ds-help", "go-ipfs-ds-help", "datastore utility functions"], - ["ipfs/go-ds-flatfs", "go-ds-flatfs", "a filesystem-based datastore"], - ["ipfs/go-ds-measure", "go-ds-measure", "a metric-collecting database adapter"], - ["ipfs/go-ds-leveldb", "go-ds-leveldb", "a leveldb based datastore"], - ["ipfs/go-ds-badger", "go-ds-badger", "a badgerdb based datastore"], - - "Namesys", - ["ipfs/go-ipns", "go-ipns", "IPNS datastructures and validation logic"], - - "Repo", - ["ipfs/go-fs-lock", "go-fs-lock", "lockfile management functions"], - ["ipfs/fs-repo-migrations", "fs-repo-migrations", "repo migrations"], - - "IPLD", - ["ipfs/go-block-format", "go-block-format", "block interfaces and implementations"], - ["ipfs/go-ipfs-blockstore", "go-ipfs-blockstore", "blockstore interfaces and implementations"], - ["ipfs/go-ipld-format", "go-ipld-format", "IPLD interfaces"], - ["ipfs/go-ipld-cbor", "go-ipld-cbor", "IPLD-CBOR implementation"], - ["ipfs/go-ipld-git", "go-ipld-git", "IPLD-Git implementation"], - ["ipfs/go-merkledag", "go-merkledag", "IPLD-Merkledag implementation (and then some)"], - - "Commands", - ["ipfs/go-ipfs-cmds", "go-ipfs-cmds", "CLI & HTTP commands library"], - ["ipfs/go-ipfs-files", "go-ipfs-files", "CLI & HTTP commands library"], - ["ipfs/go-ipfs-api", "go-ipfs-api", "an old, stable shell for the IPFS HTTP API"], - ["ipfs/go-ipfs-http-client", "go-ipfs-http-client", "a new, unstable shell for the IPFS HTTP API"], - ["ipfs/interface-go-ipfs-core", "interface-go-ipfs-core", "core go-ipfs API interface definitions"], - - "Metrics & Logging", - ["ipfs/go-metrics-interface", "go-metrics-interface", "metrics collection interfaces"], - ["ipfs/go-metrics-prometheus", "go-metrics-prometheus", "prometheus-backed metrics collector"], - ["ipfs/go-log", "go-log", "logging framework"], - - "Generics/Utils", - ["ipfs/go-ipfs-routing", "go-ipfs-routing", "routing (content, peer, value) helpers"], - ["ipfs/go-ipfs-util", "go-ipfs-util", "the kitchen sink"], - ["ipfs/go-ipfs-addr", "go-ipfs-addr", "utility functions for parsing IPFS multiaddrs"] - ] -} diff --git a/peering/peering.go b/peering/peering.go deleted file mode 100644 index 34647d63c13..00000000000 --- a/peering/peering.go +++ /dev/null @@ -1,325 +0,0 @@ -package peering - -import ( - "context" - "errors" - "math/rand" - "strconv" - "sync" - "time" - - "github.com/ipfs/go-log" - "github.com/libp2p/go-libp2p/core/host" - "github.com/libp2p/go-libp2p/core/network" - "github.com/libp2p/go-libp2p/core/peer" - "github.com/multiformats/go-multiaddr" -) - -// Seed the random number generator. -// -// We don't need good randomness, but we do need randomness. -const ( - // maxBackoff is the maximum time between reconnect attempts. - maxBackoff = 10 * time.Minute - // The backoff will be cut off when we get within 10% of the actual max. - // If we go over the max, we'll adjust the delay down to a random value - // between 90-100% of the max backoff. - maxBackoffJitter = 10 // % - connmgrTag = "ipfs-peering" - // This needs to be sufficient to prevent two sides from simultaneously - // dialing. - initialDelay = 5 * time.Second -) - -var logger = log.Logger("peering") - -type State uint - -func (s State) String() string { - switch s { - case StateInit: - return "init" - case StateRunning: - return "running" - case StateStopped: - return "stopped" - default: - return "unknown peering state: " + strconv.FormatUint(uint64(s), 10) - } -} - -const ( - StateInit State = iota - StateRunning - StateStopped -) - -// peerHandler keeps track of all state related to a specific "peering" peer. -type peerHandler struct { - peer peer.ID - host host.Host - ctx context.Context - cancel context.CancelFunc - - mu sync.Mutex - addrs []multiaddr.Multiaddr - reconnectTimer *time.Timer - - nextDelay time.Duration -} - -// setAddrs sets the addresses for this peer. -func (ph *peerHandler) setAddrs(addrs []multiaddr.Multiaddr) { - // Not strictly necessary, but it helps to not trust the calling code. - addrCopy := make([]multiaddr.Multiaddr, len(addrs)) - copy(addrCopy, addrs) - - ph.mu.Lock() - defer ph.mu.Unlock() - ph.addrs = addrCopy -} - -// getAddrs returns a shared slice of addresses for this peer. Do not modify. -func (ph *peerHandler) getAddrs() []multiaddr.Multiaddr { - ph.mu.Lock() - defer ph.mu.Unlock() - return ph.addrs -} - -// stop permanently stops the peer handler. -func (ph *peerHandler) stop() { - ph.cancel() - - ph.mu.Lock() - defer ph.mu.Unlock() - if ph.reconnectTimer != nil { - ph.reconnectTimer.Stop() - ph.reconnectTimer = nil - } -} - -func (ph *peerHandler) nextBackoff() time.Duration { - if ph.nextDelay < maxBackoff { - ph.nextDelay += ph.nextDelay/2 + time.Duration(rand.Int63n(int64(ph.nextDelay))) - } - - // If we've gone over the max backoff, reduce it under the max. - if ph.nextDelay > maxBackoff { - ph.nextDelay = maxBackoff - // randomize the backoff a bit (10%). - ph.nextDelay -= time.Duration(rand.Int63n(int64(maxBackoff) * maxBackoffJitter / 100)) - } - - return ph.nextDelay -} - -func (ph *peerHandler) reconnect() { - // Try connecting - addrs := ph.getAddrs() - logger.Debugw("reconnecting", "peer", ph.peer, "addrs", addrs) - - err := ph.host.Connect(ph.ctx, peer.AddrInfo{ID: ph.peer, Addrs: addrs}) - if err != nil { - logger.Debugw("failed to reconnect", "peer", ph.peer, "error", err) - // Ok, we failed. Extend the timeout. - ph.mu.Lock() - if ph.reconnectTimer != nil { - // Only counts if the reconnectTimer still exists. If not, a - // connection _was_ somehow established. - ph.reconnectTimer.Reset(ph.nextBackoff()) - } - // Otherwise, someone else has stopped us so we can assume that - // we're either connected or someone else will start us. - ph.mu.Unlock() - } - - // Always call this. We could have connected since we processed the - // error. - ph.stopIfConnected() -} - -func (ph *peerHandler) stopIfConnected() { - ph.mu.Lock() - defer ph.mu.Unlock() - - if ph.reconnectTimer != nil && ph.host.Network().Connectedness(ph.peer) == network.Connected { - logger.Debugw("successfully reconnected", "peer", ph.peer) - ph.reconnectTimer.Stop() - ph.reconnectTimer = nil - ph.nextDelay = initialDelay - } -} - -// startIfDisconnected is the inverse of stopIfConnected. -func (ph *peerHandler) startIfDisconnected() { - ph.mu.Lock() - defer ph.mu.Unlock() - - if ph.reconnectTimer == nil && ph.host.Network().Connectedness(ph.peer) != network.Connected { - logger.Debugw("disconnected from peer", "peer", ph.peer) - // Always start with a short timeout so we can stagger things a bit. - ph.reconnectTimer = time.AfterFunc(ph.nextBackoff(), ph.reconnect) - } -} - -// PeeringService maintains connections to specified peers, reconnecting on -// disconnect with a back-off. -type PeeringService struct { - host host.Host - - mu sync.RWMutex - peers map[peer.ID]*peerHandler - state State -} - -// NewPeeringService constructs a new peering service. Peers can be added and -// removed immediately, but connections won't be formed until `Start` is called. -func NewPeeringService(host host.Host) *PeeringService { - return &PeeringService{host: host, peers: make(map[peer.ID]*peerHandler)} -} - -// Start starts the peering service, connecting and maintaining connections to -// all registered peers. It returns an error if the service has already been -// stopped. -func (ps *PeeringService) Start() error { - ps.mu.Lock() - defer ps.mu.Unlock() - - switch ps.state { - case StateInit: - logger.Infow("starting") - case StateRunning: - return nil - case StateStopped: - return errors.New("already stopped") - } - ps.host.Network().Notify((*netNotifee)(ps)) - ps.state = StateRunning - for _, handler := range ps.peers { - go handler.startIfDisconnected() - } - return nil -} - -// GetState get the State of the PeeringService. -func (ps *PeeringService) GetState() State { - ps.mu.RLock() - defer ps.mu.RUnlock() - return ps.state -} - -// Stop stops the peering service. -func (ps *PeeringService) Stop() error { - ps.host.Network().StopNotify((*netNotifee)(ps)) - ps.mu.Lock() - defer ps.mu.Unlock() - - switch ps.state { - case StateInit, StateRunning: - logger.Infow("stopping") - for _, handler := range ps.peers { - handler.stop() - } - ps.state = StateStopped - } - return nil -} - -// AddPeer adds a peer to the peering service. This function may be safely -// called at any time: before the service is started, while running, or after it -// stops. -// -// Add peer may also be called multiple times for the same peer. The new -// addresses will replace the old. -func (ps *PeeringService) AddPeer(info peer.AddrInfo) { - ps.mu.Lock() - defer ps.mu.Unlock() - - if handler, ok := ps.peers[info.ID]; ok { - logger.Infow("updating addresses", "peer", info.ID, "addrs", info.Addrs) - handler.setAddrs(info.Addrs) - } else { - logger.Infow("peer added", "peer", info.ID, "addrs", info.Addrs) - ps.host.ConnManager().Protect(info.ID, connmgrTag) - - handler = &peerHandler{ - host: ps.host, - peer: info.ID, - addrs: info.Addrs, - nextDelay: initialDelay, - } - handler.ctx, handler.cancel = context.WithCancel(context.Background()) - ps.peers[info.ID] = handler - switch ps.state { - case StateRunning: - go handler.startIfDisconnected() - case StateStopped: - // We still construct everything in this state because - // it's easier to reason about. But we should still free - // resources. - handler.cancel() - } - } -} - -// ListPeers lists peers in the peering service. -func (ps *PeeringService) ListPeers() []peer.AddrInfo { - ps.mu.RLock() - defer ps.mu.RUnlock() - - out := make([]peer.AddrInfo, 0, len(ps.peers)) - for id, addrs := range ps.peers { - ai := peer.AddrInfo{ID: id} - ai.Addrs = append(ai.Addrs, addrs.addrs...) - out = append(out, ai) - } - return out -} - -// RemovePeer removes a peer from the peering service. This function may be -// safely called at any time: before the service is started, while running, or -// after it stops. -func (ps *PeeringService) RemovePeer(id peer.ID) { - ps.mu.Lock() - defer ps.mu.Unlock() - - if handler, ok := ps.peers[id]; ok { - logger.Infow("peer removed", "peer", id) - ps.host.ConnManager().Unprotect(id, connmgrTag) - - handler.stop() - delete(ps.peers, id) - } -} - -type netNotifee PeeringService - -func (nn *netNotifee) Connected(_ network.Network, c network.Conn) { - ps := (*PeeringService)(nn) - - p := c.RemotePeer() - ps.mu.RLock() - defer ps.mu.RUnlock() - - if handler, ok := ps.peers[p]; ok { - // use a goroutine to avoid blocking events. - go handler.stopIfConnected() - } -} - -func (nn *netNotifee) Disconnected(_ network.Network, c network.Conn) { - ps := (*PeeringService)(nn) - - p := c.RemotePeer() - ps.mu.RLock() - defer ps.mu.RUnlock() - - if handler, ok := ps.peers[p]; ok { - // use a goroutine to avoid blocking events. - go handler.startIfDisconnected() - } -} -func (nn *netNotifee) OpenedStream(network.Network, network.Stream) {} -func (nn *netNotifee) ClosedStream(network.Network, network.Stream) {} -func (nn *netNotifee) Listen(network.Network, multiaddr.Multiaddr) {} -func (nn *netNotifee) ListenClose(network.Network, multiaddr.Multiaddr) {} diff --git a/peering/peering_test.go b/peering/peering_test.go deleted file mode 100644 index de07789c216..00000000000 --- a/peering/peering_test.go +++ /dev/null @@ -1,172 +0,0 @@ -package peering - -import ( - "context" - "testing" - "time" - - "github.com/libp2p/go-libp2p" - "github.com/libp2p/go-libp2p/core/host" - "github.com/libp2p/go-libp2p/core/network" - "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/p2p/net/connmgr" - - "github.com/stretchr/testify/require" -) - -func newNode(t *testing.T) host.Host { - cm, err := connmgr.NewConnManager(1, 100, connmgr.WithGracePeriod(0)) - require.NoError(t, err) - h, err := libp2p.New( - libp2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0"), - // We'd like to set the connection manager low water to 0, but - // that would disable the connection manager. - libp2p.ConnectionManager(cm), - ) - require.NoError(t, err) - return h -} - -func TestPeeringService(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - h1 := newNode(t) - ps1 := NewPeeringService(h1) - - h2 := newNode(t) - h3 := newNode(t) - h4 := newNode(t) - - // peer 1 -> 2 - ps1.AddPeer(peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}) - require.Contains(t, ps1.ListPeers(), peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}) - - // We haven't started so we shouldn't have any peers. - require.Never(t, func() bool { - return len(h1.Network().Peers()) > 0 - }, 100*time.Millisecond, 1*time.Second, "expected host 1 to have no peers") - - // Use p4 to take up the one slot we have in the connection manager. - for _, h := range []host.Host{h1, h2} { - require.NoError(t, h.Connect(ctx, peer.AddrInfo{ID: h4.ID(), Addrs: h4.Addrs()})) - h.ConnManager().TagPeer(h4.ID(), "sticky-peer", 1000) - } - - // Now start. - require.NoError(t, ps1.Start()) - // starting twice is fine. - require.NoError(t, ps1.Start()) - - // We should eventually connect. - t.Logf("waiting for h1 to connect to h2") - require.Eventually(t, func() bool { - return h1.Network().Connectedness(h2.ID()) == network.Connected - }, 30*time.Second, 10*time.Millisecond) - - // Now explicitly connect to h3. - t.Logf("waiting for h1's connection to h3 to work") - require.NoError(t, h1.Connect(ctx, peer.AddrInfo{ID: h3.ID(), Addrs: h3.Addrs()})) - require.Eventually(t, func() bool { - return h1.Network().Connectedness(h3.ID()) == network.Connected - }, 30*time.Second, 100*time.Millisecond) - - require.Len(t, h1.Network().Peers(), 3) - - // force a disconnect - h1.ConnManager().TrimOpenConns(ctx) - - // Should disconnect from h3. - t.Logf("waiting for h1's connection to h3 to disconnect") - require.Eventually(t, func() bool { - return h1.Network().Connectedness(h3.ID()) != network.Connected - }, 5*time.Second, 10*time.Millisecond) - - // Should remain connected to p2 - require.Never(t, func() bool { - return h1.Network().Connectedness(h2.ID()) != network.Connected - }, 5*time.Second, 1*time.Second) - - // Now force h2 to disconnect (we have an asymmetric peering). - conns := h2.Network().ConnsToPeer(h1.ID()) - require.NotEmpty(t, conns) - h2.ConnManager().TrimOpenConns(ctx) - - // All conns to peer should eventually close. - t.Logf("waiting for all connections to close") - for _, c := range conns { - require.Eventually(t, func() bool { - s, err := c.NewStream(context.Background()) - if s != nil { - _ = s.Reset() - } - return err != nil - }, 5*time.Second, 10*time.Millisecond) - } - - // Should eventually re-connect. - require.Eventually(t, func() bool { - return h1.Network().Connectedness(h2.ID()) == network.Connected - }, 30*time.Second, 1*time.Second) - - // Unprotect 2 from 1. - ps1.RemovePeer(h2.ID()) - require.NotContains(t, ps1.ListPeers(), peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}) - - // Trim connections. - h1.ConnManager().TrimOpenConns(ctx) - - // Should disconnect - t.Logf("waiting for h1 to disconnect from h2") - require.Eventually(t, func() bool { - return h1.Network().Connectedness(h2.ID()) != network.Connected - }, 5*time.Second, 10*time.Millisecond) - - // Should never reconnect. - t.Logf("ensuring h1 is not connected to h2 again") - require.Never(t, func() bool { - return h1.Network().Connectedness(h2.ID()) == network.Connected - }, 20*time.Second, 1*time.Second) - - // Until added back - ps1.AddPeer(peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}) - require.Contains(t, ps1.ListPeers(), peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}) - ps1.AddPeer(peer.AddrInfo{ID: h3.ID(), Addrs: h3.Addrs()}) - require.Contains(t, ps1.ListPeers(), peer.AddrInfo{ID: h3.ID(), Addrs: h3.Addrs()}) - t.Logf("wait for h1 to connect to h2 and h3 again") - require.Eventually(t, func() bool { - return h1.Network().Connectedness(h2.ID()) == network.Connected - }, 30*time.Second, 1*time.Second) - require.Eventually(t, func() bool { - return h1.Network().Connectedness(h3.ID()) == network.Connected - }, 30*time.Second, 1*time.Second) - - // Should be able to repeatedly stop. - require.NoError(t, ps1.Stop()) - require.NoError(t, ps1.Stop()) - - // Adding and removing should work after stopping. - ps1.AddPeer(peer.AddrInfo{ID: h4.ID(), Addrs: h4.Addrs()}) - require.Contains(t, ps1.ListPeers(), peer.AddrInfo{ID: h4.ID(), Addrs: h4.Addrs()}) - ps1.RemovePeer(h2.ID()) - require.NotContains(t, ps1.ListPeers(), peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}) -} - -func TestNextBackoff(t *testing.T) { - minMaxBackoff := (100 - maxBackoffJitter) / 100 * maxBackoff - for x := 0; x < 1000; x++ { - ph := peerHandler{nextDelay: time.Second} - for min, max := time.Second*3/2, time.Second*5/2; min < minMaxBackoff; min, max = min*3/2, max*5/2 { - b := ph.nextBackoff() - if b > max || b < min { - t.Errorf("expected backoff %s to be between %s and %s", b, min, max) - } - } - for i := 0; i < 100; i++ { - b := ph.nextBackoff() - if b < minMaxBackoff || b > maxBackoff { - t.Fatal("failed to stay within max bounds") - } - } - } -} diff --git a/plugin/loader/preload.go b/plugin/loader/preload.go index 4304862119d..2ad84e59489 100644 --- a/plugin/loader/preload.go +++ b/plugin/loader/preload.go @@ -7,6 +7,7 @@ import ( pluginfxtest "github.com/ipfs/kubo/plugin/plugins/fxtest" pluginipldgit "github.com/ipfs/kubo/plugin/plugins/git" pluginlevelds "github.com/ipfs/kubo/plugin/plugins/levelds" + pluginnopfs "github.com/ipfs/kubo/plugin/plugins/nopfs" pluginpeerlog "github.com/ipfs/kubo/plugin/plugins/peerlog" ) @@ -22,4 +23,5 @@ func init() { Preload(pluginlevelds.Plugins...) Preload(pluginpeerlog.Plugins...) Preload(pluginfxtest.Plugins...) + Preload(pluginnopfs.Plugins...) } diff --git a/plugin/loader/preload_list b/plugin/loader/preload_list index c18ea80ccd5..462a3f39337 100644 --- a/plugin/loader/preload_list +++ b/plugin/loader/preload_list @@ -11,3 +11,4 @@ flatfs github.com/ipfs/kubo/plugin/plugins/flatfs * levelds github.com/ipfs/kubo/plugin/plugins/levelds * peerlog github.com/ipfs/kubo/plugin/plugins/peerlog * fxtest github.com/ipfs/kubo/plugin/plugins/fxtest * +nopfs github.com/ipfs/kubo/plugin/plugins/nopfs * \ No newline at end of file diff --git a/plugin/plugins/nopfs/nopfs.go b/plugin/plugins/nopfs/nopfs.go new file mode 100644 index 00000000000..64350830f94 --- /dev/null +++ b/plugin/plugins/nopfs/nopfs.go @@ -0,0 +1,85 @@ +package nopfs + +import ( + "os" + "path/filepath" + + "github.com/ipfs-shipyard/nopfs" + "github.com/ipfs-shipyard/nopfs/ipfs" + "github.com/ipfs/kubo/config" + "github.com/ipfs/kubo/core" + "github.com/ipfs/kubo/core/node" + "github.com/ipfs/kubo/plugin" + "go.uber.org/fx" +) + +// Plugins sets the list of plugins to be loaded. +var Plugins = []plugin.Plugin{ + &nopfsPlugin{}, +} + +// fxtestPlugin is used for testing the fx plugin. +// It merely adds an fx option that logs a debug statement, so we can verify that it works in tests. +type nopfsPlugin struct{} + +var _ plugin.PluginFx = (*nopfsPlugin)(nil) + +func (p *nopfsPlugin) Name() string { + return "nopfs" +} + +func (p *nopfsPlugin) Version() string { + return "0.0.10" +} + +func (p *nopfsPlugin) Init(env *plugin.Environment) error { + return nil +} + +// MakeBlocker is a factory for the blocker so that it can be provided with Fx. +func MakeBlocker() (*nopfs.Blocker, error) { + ipfsPath, err := config.PathRoot() + if err != nil { + return nil, err + } + + defaultFiles, err := nopfs.GetDenylistFiles() + if err != nil { + return nil, err + } + + kuboFiles, err := nopfs.GetDenylistFilesInDir(filepath.Join(ipfsPath, "denylists")) + if err != nil { + return nil, err + } + + files := append(defaultFiles, kuboFiles...) + + return nopfs.NewBlocker(files) +} + +// PathResolvers returns wrapped PathResolvers for Kubo. +func PathResolvers(fetchers node.FetchersIn, blocker *nopfs.Blocker) node.PathResolversOut { + res := node.PathResolverConfig(fetchers) + return node.PathResolversOut{ + IPLDPathResolver: ipfs.WrapResolver(res.IPLDPathResolver, blocker), + UnixFSPathResolver: ipfs.WrapResolver(res.UnixFSPathResolver, blocker), + OfflineIPLDPathResolver: ipfs.WrapResolver(res.OfflineIPLDPathResolver, blocker), + OfflineUnixFSPathResolver: ipfs.WrapResolver(res.OfflineUnixFSPathResolver, blocker), + } +} + +func (p *nopfsPlugin) Options(info core.FXNodeInfo) ([]fx.Option, error) { + if os.Getenv("IPFS_CONTENT_BLOCKING_DISABLE") != "" { + return info.FXOptions, nil + } + + opts := append( + info.FXOptions, + fx.Provide(MakeBlocker), + fx.Decorate(ipfs.WrapBlockService), + fx.Decorate(ipfs.WrapNameSystem), + fx.Decorate(PathResolvers), + ) + return opts, nil +} diff --git a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go index b35cab683d8..cd6a5182ee1 100644 --- a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go +++ b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go @@ -7,14 +7,14 @@ import ( "io" "net/url" "os" - "path" + gopath "path" "strings" "sync" iface "github.com/ipfs/boxo/coreiface" "github.com/ipfs/boxo/coreiface/options" - ipath "github.com/ipfs/boxo/coreiface/path" "github.com/ipfs/boxo/files" + "github.com/ipfs/boxo/path" "github.com/ipfs/kubo/config" "github.com/ipfs/kubo/core" "github.com/ipfs/kubo/core/coreapi" @@ -46,7 +46,7 @@ type IpfsFetcher struct { ipfsTmpDir string ipfsStopFunc func() - fetched []ipath.Path + fetched []path.Path mutex sync.Mutex addrInfo peer.AddrInfo @@ -108,7 +108,7 @@ func (f *IpfsFetcher) Fetch(ctx context.Context, filePath string) ([]byte, error return nil, f.openErr } - iPath, err := parsePath(path.Join(f.distPath, filePath)) + iPath, err := parsePath(gopath.Join(f.distPath, filePath)) if err != nil { return nil, err } @@ -156,13 +156,13 @@ func (f *IpfsFetcher) AddrInfo() peer.AddrInfo { } // FetchedPaths returns the IPFS paths of all items fetched by this fetcher. -func (f *IpfsFetcher) FetchedPaths() []ipath.Path { +func (f *IpfsFetcher) FetchedPaths() []path.Path { f.mutex.Lock() defer f.mutex.Unlock() return f.fetched } -func (f *IpfsFetcher) recordFetched(fetchedPath ipath.Path) { +func (f *IpfsFetcher) recordFetched(fetchedPath path.Path) { // Mutex protects against update by concurrent calls to Fetch f.mutex.Lock() defer f.mutex.Unlock() @@ -267,9 +267,8 @@ func (f *IpfsFetcher) startTempNode(ctx context.Context) error { return nil } -func parsePath(fetchPath string) (ipath.Path, error) { - ipfsPath := ipath.New(fetchPath) - if ipfsPath.IsValid() == nil { +func parsePath(fetchPath string) (path.Path, error) { + if ipfsPath, err := path.NewPath(fetchPath); err == nil { return ipfsPath, nil } @@ -280,11 +279,10 @@ func parsePath(fetchPath string) (ipath.Path, error) { switch proto := u.Scheme; proto { case "ipfs", "ipld", "ipns": - ipfsPath = ipath.New(path.Join("/", proto, u.Host, u.Path)) + return path.NewPath(gopath.Join("/", proto, u.Host, u.Path)) default: return nil, fmt.Errorf("%q is not an IPFS path", fetchPath) } - return ipfsPath, ipfsPath.IsValid() } func readIpfsConfig(repoRoot *string, userConfigFile string) (bootstrap []string, peers []peer.AddrInfo) { diff --git a/tar/format.go b/tar/format.go index bde92398057..a1fe455b4a5 100644 --- a/tar/format.go +++ b/tar/format.go @@ -6,13 +6,13 @@ import ( "context" "errors" "io" + "path" "strings" dag "github.com/ipfs/boxo/ipld/merkledag" "github.com/ipfs/boxo/ipld/merkledag/dagutils" importer "github.com/ipfs/boxo/ipld/unixfs/importer" uio "github.com/ipfs/boxo/ipld/unixfs/io" - path "github.com/ipfs/boxo/path" chunker "github.com/ipfs/boxo/chunker" ipld "github.com/ipfs/go-ipld-format" @@ -95,11 +95,11 @@ func ImportTar(ctx context.Context, r io.Reader, ds ipld.DAGService) (*dag.Proto // adds a '-' to the beginning of each path element so we can use 'data' as a // special link in the structure without having to worry about. func escapePath(pth string) string { - elems := path.SplitList(strings.Trim(pth, "/")) + elems := strings.Split(strings.Trim(pth, "/"), "/") for i, e := range elems { elems[i] = "-" + e } - return path.Join(elems) + return path.Join(elems...) } type tarReader struct { diff --git a/test/cli/content_blocking_test.go b/test/cli/content_blocking_test.go new file mode 100644 index 00000000000..ddb7c951e88 --- /dev/null +++ b/test/cli/content_blocking_test.go @@ -0,0 +1,303 @@ +package cli + +import ( + "context" + "fmt" + "io" + "log" + "net/http" + "net/url" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/ipfs/kubo/test/cli/harness" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/peer" + libp2phttp "github.com/libp2p/go-libp2p/p2p/http" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestContentBlocking(t *testing.T) { + // NOTE: we can't run this with t.Parallel() because we set IPFS_NS_MAP + // and running in parallel could impact other tests + + const blockedMsg = "blocked and cannot be provided" + const statusExpl = "specific HTTP error code is expected" + const bodyExpl = "Error message informing about content block is expected" + + h := harness.NewT(t) + + // Init IPFS_PATH + node := h.NewNode().Init("--empty-repo", "--profile=test") + + // Create CIDs we use in test + h.WriteFile("blocked-dir/subdir/indirectly-blocked-file.txt", "indirectly blocked file content") + parentDirCID := node.IPFS("add", "--raw-leaves", "-Q", "-r", filepath.Join(h.Dir, "blocked-dir")).Stdout.Trimmed() + + h.WriteFile("directly-blocked-file.txt", "directly blocked file content") + blockedCID := node.IPFS("add", "--raw-leaves", "-Q", filepath.Join(h.Dir, "directly-blocked-file.txt")).Stdout.Trimmed() + + h.WriteFile("not-blocked-file.txt", "not blocked file content") + allowedCID := node.IPFS("add", "--raw-leaves", "-Q", filepath.Join(h.Dir, "not-blocked-file.txt")).Stdout.Trimmed() + + // Create denylist at $IPFS_PATH/denylists/test.deny + denylistTmp := h.WriteToTemp("name: test list\n---\n" + + "//QmX9dhRcQcKUw3Ws8485T5a9dtjrSCQaUAHnG4iK9i4ceM\n" + // Double hash (sha256) CID block: base58btc(sha256-multihash(QmVTF1yEejXd9iMgoRTFDxBv7HAz9kuZcQNBzHrceuK9HR)) + "//gW813G35CnLsy7gRYYHuf63hrz71U1xoLFDVeV7actx6oX\n" + // Double hash (blake3) Path block under blake3 root CID: base58btc(blake3-multihash(gW7Nhu4HrfDtphEivm3Z9NNE7gpdh5Tga8g6JNZc1S8E47/path)) + "//8526ba05eec55e28f8db5974cc891d0d92c8af69d386fc6464f1e9f372caf549\n" + // Legacy CID double-hash block: sha256(bafkqahtcnrxwg23fmqqgi33vmjwgk2dbonuca3dfm5qwg6jamnuwicq/) + "//e5b7d2ce2594e2e09901596d8e1f29fa249b74c8c9e32ea01eda5111e4d33f07\n" + // Legacy Path double-hash block: sha256(bafyaagyscufaqalqaacauaqiaejao43vmjygc5didacauaqiae/subpath) + "/ipfs/" + blockedCID + "\n" + // block specific CID + "/ipfs/" + parentDirCID + "/subdir*\n" + // block only specific subpath + "/ipns/blocked-cid.example.com\n" + + "/ipns/blocked-dnslink.example.com\n") + + if err := os.MkdirAll(filepath.Join(node.Dir, "denylists"), 0o777); err != nil { + log.Panicf("failed to create denylists dir: %s", err.Error()) + } + if err := os.Rename(denylistTmp, filepath.Join(node.Dir, "denylists", "test.deny")); err != nil { + log.Panicf("failed to create test denylist: %s", err.Error()) + } + + // Add two entries to namesys resolution cache + // /ipns/blocked-cid.example.com point at a blocked CID (to confirm blocking impacts /ipns resolution) + // /ipns/blocked-dnslink.example.com with safe CID (to test blocking of /ipns/ paths) + os.Setenv("IPFS_NS_MAP", "blocked-cid.example.com:/ipfs/"+blockedCID+",blocked-dnslink.example.com/ipns/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn") + defer os.Unsetenv("IPFS_NS_MAP") + + // Enable GatewayOverLibp2p as we want to test denylist there too + node.IPFS("config", "--json", "Experimental.GatewayOverLibp2p", "true") + + // Start daemon, it should pick up denylist from $IPFS_PATH/denylists/test.deny + node.StartDaemon() // we need online mode for GatewayOverLibp2p tests + client := node.GatewayClient() + + // First, confirm gateway works + t.Run("Gateway Allows CID that is not blocked", func(t *testing.T) { + t.Parallel() + resp := client.Get("/ipfs/" + allowedCID) + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, "not blocked file content", resp.Body) + }) + + // Then, does the most basic blocking case work? + t.Run("Gateway Denies directly blocked CID", func(t *testing.T) { + t.Parallel() + resp := client.Get("/ipfs/" + blockedCID) + assert.Equal(t, http.StatusGone, resp.StatusCode, statusExpl) + assert.NotEqual(t, "directly blocked file content", resp.Body) + assert.Contains(t, resp.Body, blockedMsg, bodyExpl) + }) + + // Confirm parent of blocked subpath is not blocked + t.Run("Gateway Allows parent Path that is not blocked", func(t *testing.T) { + t.Parallel() + resp := client.Get("/ipfs/" + parentDirCID) + assert.Equal(t, http.StatusOK, resp.StatusCode) + }) + + // Ok, now the full list of test cases we want to cover in both CLI and Gateway + testCases := []struct { + name string + path string + }{ + { + name: "directly blocked CID", + path: "/ipfs/" + blockedCID, + }, + { + name: "indirectly blocked file (on a blocked subpath)", + path: "/ipfs/" + parentDirCID + "/subdir/indirectly-blocked-file.txt", + }, + { + name: "/ipns path that resolves to a blocked CID", + path: "/ipns/blocked-cid.example.com", + }, + { + name: "/ipns Path that is blocked by DNSLink name", + path: "/ipns/blocked-dnslink.example.com", + }, + { + name: "double-hash CID block (sha256-multihash)", + path: "/ipfs/QmVTF1yEejXd9iMgoRTFDxBv7HAz9kuZcQNBzHrceuK9HR", + }, + { + name: "double-hash Path block (blake3-multihash)", + path: "/ipfs/bafyb4ieqht3b2rssdmc7sjv2cy2gfdilxkfh7623nvndziyqnawkmo266a/path", + }, + { + name: "legacy CID double-hash block (sha256)", + path: "/ipfs/bafkqahtcnrxwg23fmqqgi33vmjwgk2dbonuca3dfm5qwg6jamnuwicq", + }, + + { + name: "legacy Path double-hash block (sha256)", + path: "/ipfs/bafyaagyscufaqalqaacauaqiaejao43vmjygc5didacauaqiae/subpath", + }, + } + + // Which specific cliCmds we test against testCases + cliCmds := [][]string{ + {"block", "get"}, + {"block", "stat"}, + {"dag", "get"}, + {"dag", "export"}, + {"dag", "stat"}, + {"cat"}, + {"ls"}, + {"get"}, + {"refs"}, + } + + expectedMsg := blockedMsg + for _, testCase := range testCases { + + // Confirm that denylist is active for every command in 'cliCmds' x 'testCases' + for _, cmd := range cliCmds { + cmd := cmd + cliTestName := fmt.Sprintf("CLI '%s' denies %s", strings.Join(cmd, " "), testCase.name) + t.Run(cliTestName, func(t *testing.T) { + t.Parallel() + args := append(cmd, testCase.path) + errMsg := node.RunIPFS(args...).Stderr.Trimmed() + if !strings.Contains(errMsg, expectedMsg) { + t.Errorf("Expected STDERR error message %q, but got: %q", expectedMsg, errMsg) + } + }) + } + + // Confirm that denylist is active for every content path in 'testCases' + gwTestName := fmt.Sprintf("Gateway denies %s", testCase.name) + t.Run(gwTestName, func(t *testing.T) { + resp := client.Get(testCase.path) + assert.Equal(t, http.StatusGone, resp.StatusCode, statusExpl) + assert.Contains(t, resp.Body, blockedMsg, bodyExpl) + }) + + } + + // Extra edge cases on subdomain gateway + + t.Run("Gateway Denies /ipns Path that is blocked by DNSLink name (subdomain redirect)", func(t *testing.T) { + t.Parallel() + + gwURL, _ := url.Parse(node.GatewayURL()) + resp := client.Get("/ipns/blocked-dnslink.example.com", func(r *http.Request) { + r.Host = "localhost:" + gwURL.Port() + }) + + assert.Equal(t, http.StatusGone, resp.StatusCode, statusExpl) + assert.Contains(t, resp.Body, blockedMsg, bodyExpl) + }) + + t.Run("Gateway Denies /ipns Path that is blocked by DNSLink name (subdomain, no TLS)", func(t *testing.T) { + t.Parallel() + + gwURL, _ := url.Parse(node.GatewayURL()) + resp := client.Get("/", func(r *http.Request) { + r.Host = "blocked-dnslink.example.com.ipns.localhost:" + gwURL.Port() + }) + + assert.Equal(t, http.StatusGone, resp.StatusCode, statusExpl) + assert.Contains(t, resp.Body, blockedMsg, bodyExpl) + }) + + t.Run("Gateway Denies /ipns Path that is blocked by DNSLink name (subdomain, inlined for TLS)", func(t *testing.T) { + t.Parallel() + + gwURL, _ := url.Parse(node.GatewayURL()) + resp := client.Get("/", func(r *http.Request) { + // Inlined DNSLink to fit in single DNS label for TLS interop: + // https://specs.ipfs.tech/http-gateways/subdomain-gateway/#host-request-header + r.Host = "blocked--dnslink-example-com.ipns.localhost:" + gwURL.Port() + }) + + assert.Equal(t, http.StatusGone, resp.StatusCode, statusExpl) + assert.Contains(t, resp.Body, blockedMsg, bodyExpl) + }) + + // We need to confirm denylist is active when gateway is run in NoFetch + // mode (which usually swaps blockservice to a read-only one, and that swap + // may cause denylists to not be applied, as it is a separate code path) + t.Run("GatewayNoFetch", func(t *testing.T) { + // NOTE: we don't run this in parallel, as it requires restart with different config + + // Switch gateway to NoFetch mode + node.StopDaemon() + node.IPFS("config", "--json", "Gateway.NoFetch", "true") + node.StartDaemon() + + // update client, as the port of test node might've changed after restart + client = node.GatewayClient() + + // First, confirm gateway works + t.Run("Allows CID that is not blocked", func(t *testing.T) { + resp := client.Get("/ipfs/" + allowedCID) + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, "not blocked file content", resp.Body) + }) + + // Then, does the most basic blocking case work? + t.Run("Denies directly blocked CID", func(t *testing.T) { + resp := client.Get("/ipfs/" + blockedCID) + assert.Equal(t, http.StatusGone, resp.StatusCode, statusExpl) + assert.NotEqual(t, "directly blocked file content", resp.Body) + assert.Contains(t, resp.Body, blockedMsg, bodyExpl) + }) + + // Restore default + node.StopDaemon() + node.IPFS("config", "--json", "Gateway.NoFetch", "false") + node.StartDaemon() + client = node.GatewayClient() + }) + + // We need to confirm denylist is active on the + // trustless gateway exposed over libp2p + // when Experimental.GatewayOverLibp2p=true + // (https://github.com/ipfs/kubo/blob/master/docs/experimental-features.md#http-gateway-over-libp2p) + // NOTE: this type fo gateway is hardcoded to be NoFetch: it does not fetch + // data that is not in local store, so we only need to run it once: a + // simple smoke-test for allowed CID and blockedCID. + t.Run("GatewayOverLibp2p", func(t *testing.T) { + t.Parallel() + + // Create libp2p client that connects to our node over + // /http1.1 and then talks gateway semantics over the /ipfs/gateway sub-protocol + clientHost, err := libp2p.New(libp2p.NoListenAddrs) + require.NoError(t, err) + err = clientHost.Connect(context.Background(), peer.AddrInfo{ + ID: node.PeerID(), + Addrs: node.SwarmAddrs(), + }) + require.NoError(t, err) + + libp2pClient, err := (&libp2phttp.Host{StreamHost: clientHost}).NamespacedClient("/ipfs/gateway", peer.AddrInfo{ID: node.PeerID()}) + require.NoError(t, err) + + t.Run("Serves Allowed CID", func(t *testing.T) { + t.Parallel() + resp, err := libp2pClient.Get(fmt.Sprintf("/ipfs/%s?format=raw", allowedCID)) + require.NoError(t, err) + defer resp.Body.Close() + assert.Equal(t, http.StatusOK, resp.StatusCode) + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, string(body), "not blocked file content", bodyExpl) + }) + + t.Run("Denies Blocked CID", func(t *testing.T) { + t.Parallel() + resp, err := libp2pClient.Get(fmt.Sprintf("/ipfs/%s?format=raw", blockedCID)) + require.NoError(t, err) + defer resp.Body.Close() + assert.Equal(t, http.StatusGone, resp.StatusCode, statusExpl) + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + assert.NotEqual(t, string(body), "directly blocked file content") + assert.Contains(t, string(body), blockedMsg, bodyExpl) + }) + }) +} diff --git a/test/cli/content_routing_http_test.go b/test/cli/content_routing_http_test.go index 652c8ac59eb..aea5c41caeb 100644 --- a/test/cli/content_routing_http_test.go +++ b/test/cli/content_routing_http_test.go @@ -43,11 +43,11 @@ func (r *fakeHTTPContentRouter) ProvideBitswap(ctx context.Context, req *server. return 0, nil } -func (r *fakeHTTPContentRouter) FindPeers(ctx context.Context, pid peer.ID, limit int) (iter.ResultIter[types.Record], error) { +func (r *fakeHTTPContentRouter) FindPeers(ctx context.Context, pid peer.ID, limit int) (iter.ResultIter[*types.PeerRecord], error) { r.m.Lock() defer r.m.Unlock() r.findPeersCalls++ - return iter.FromSlice([]iter.Result[types.Record]{}), nil + return iter.FromSlice([]iter.Result[*types.PeerRecord]{}), nil } func (r *fakeHTTPContentRouter) GetIPNS(ctx context.Context, name ipns.Name) (*ipns.Record, error) { diff --git a/test/cli/delegated_routing_v1_http_server_test.go b/test/cli/delegated_routing_v1_http_server_test.go index 440510c1f00..f2bd98cb77b 100644 --- a/test/cli/delegated_routing_v1_http_server_test.go +++ b/test/cli/delegated_routing_v1_http_server_test.go @@ -80,7 +80,7 @@ func TestRoutingV1Server(t *testing.T) { assert.IsType(t, records[0].GetSchema(), records[0].GetSchema()) assert.IsType(t, records[0], &types.PeerRecord{}) - peer := records[0].(*types.PeerRecord) + peer := records[0] assert.Equal(t, nodes[2].PeerID().String(), peer.ID.String()) assert.NotEmpty(t, peer.Addrs) }) diff --git a/test/cli/gateway_range_test.go b/test/cli/gateway_range_test.go index 7440e63411a..2d8ce1a3eff 100644 --- a/test/cli/gateway_range_test.go +++ b/test/cli/gateway_range_test.go @@ -41,7 +41,7 @@ func TestGatewayHAMTDirectory(t *testing.T) { assert.Equal(t, http.StatusOK, resp.StatusCode) } -func TestGatewayMultiRange(t *testing.T) { +func TestGatewayHAMTRanges(t *testing.T) { t.Parallel() const ( @@ -65,11 +65,36 @@ func TestGatewayMultiRange(t *testing.T) { err = node.IPFSDagImport(r, fixtureCid) assert.NoError(t, err) - // Succeeds fetching a range of blocks we have - resp := client.Get(fmt.Sprintf("/ipfs/%s", fileCid), func(r *http.Request) { - r.Header.Set("Range", "bytes=1276-1279, 29839070-29839080") + t.Run("Succeeds Fetching Range", func(t *testing.T) { + t.Parallel() + + resp := client.Get(fmt.Sprintf("/ipfs/%s", fileCid), func(r *http.Request) { + r.Header.Set("Range", "bytes=1276-1279") + }) + assert.Equal(t, http.StatusPartialContent, resp.StatusCode) + assert.Equal(t, "bytes 1276-1279/109266405", resp.Headers.Get("Content-Range")) + assert.Equal(t, "iana", resp.Body) + }) + + t.Run("Succeeds Fetching Second Range", func(t *testing.T) { + t.Parallel() + + resp := client.Get(fmt.Sprintf("/ipfs/%s", fileCid), func(r *http.Request) { + r.Header.Set("Range", "bytes=29839070-29839080") + }) + assert.Equal(t, http.StatusPartialContent, resp.StatusCode) + assert.Equal(t, "bytes 29839070-29839080/109266405", resp.Headers.Get("Content-Range")) + assert.Equal(t, "EXAMPLE.COM", resp.Body) + }) + + t.Run("Succeeds Fetching First Range of Multi-range Request", func(t *testing.T) { + t.Parallel() + + resp := client.Get(fmt.Sprintf("/ipfs/%s", fileCid), func(r *http.Request) { + r.Header.Set("Range", "bytes=1276-1279, 29839070-29839080") + }) + assert.Equal(t, http.StatusPartialContent, resp.StatusCode) + assert.Equal(t, "bytes 1276-1279/109266405", resp.Headers.Get("Content-Range")) + assert.Equal(t, "iana", resp.Body) }) - assert.Equal(t, http.StatusPartialContent, resp.StatusCode) - assert.Contains(t, resp.Body, "Content-Range: bytes 1276-1279/109266405\r\nContent-Type: text/plain; charset=utf-8\r\n\r\niana\r\n") - assert.Contains(t, resp.Body, "Content-Range: bytes 29839070-29839080/109266405\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nEXAMPLE.COM\r\n") } diff --git a/test/cli/gateway_test.go b/test/cli/gateway_test.go index a1c2fa8c98b..c98c62c47eb 100644 --- a/test/cli/gateway_test.go +++ b/test/cli/gateway_test.go @@ -8,6 +8,8 @@ import ( "os" "path/filepath" "regexp" + "strconv" + "strings" "testing" "github.com/ipfs/kubo/config" @@ -169,7 +171,7 @@ func TestGateway(t *testing.T) { t.Run("IPNS", func(t *testing.T) { t.Parallel() - node.IPFS("name", "publish", "--allow-offline", cid) + node.IPFS("name", "publish", "--allow-offline", "--ttl", "42h", cid) t.Run("GET invalid IPNS root returns 500 (Internal Server Error)", func(t *testing.T) { t.Parallel() @@ -184,6 +186,17 @@ func TestGateway(t *testing.T) { assert.Equal(t, "Hello Worlds!", resp.Body) }) + t.Run("GET IPNS path has correct Cache-Control", func(t *testing.T) { + t.Parallel() + resp := client.Get("/ipns/{{.PeerID}}") + assert.Equal(t, 200, resp.StatusCode) + cacheControl := resp.Headers.Get("Cache-Control") + assert.True(t, strings.HasPrefix(cacheControl, "public, max-age=")) + maxAge, err := strconv.Atoi(strings.TrimPrefix(cacheControl, "public, max-age=")) + assert.NoError(t, err) + assert.True(t, maxAge-151200 < 60) // MaxAge within 42h and 42h-1m + }) + t.Run("GET /ipfs/ipns/{peerid} returns redirect to the valid path", func(t *testing.T) { t.Parallel() resp := client.Get("/ipfs/ipns/{{.PeerID}}?query=to-remember") @@ -408,9 +421,9 @@ func TestGateway(t *testing.T) { t.Parallel() gatewayAddr := URLStrToMultiaddr(node.GatewayURL()) res := node.RunIPFS("--api", gatewayAddr.String(), "refs", "local") - assert.Equal(t, - `Error: invalid path "local": invalid cid: selected encoding not supported`, + assert.Contains(t, res.Stderr.Trimmed(), + `Error: invalid path "local":`, ) }) diff --git a/test/dependencies/go.mod b/test/dependencies/go.mod index 509ad2c8c3a..7593700c57c 100644 --- a/test/dependencies/go.mod +++ b/test/dependencies/go.mod @@ -7,7 +7,7 @@ replace github.com/ipfs/kubo => ../../ require ( github.com/Kubuxu/gocovmerge v0.0.0-20161216165753-7ecaa51963cd github.com/golangci/golangci-lint v1.54.1 - github.com/ipfs/boxo v0.13.1 + github.com/ipfs/boxo v0.14.0 github.com/ipfs/go-cid v0.4.1 github.com/ipfs/go-cidutil v0.1.0 github.com/ipfs/go-datastore v0.6.0 @@ -107,7 +107,7 @@ require ( github.com/google/go-cmp v0.5.9 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect @@ -120,20 +120,20 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/huin/goupnp v1.2.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect - github.com/ipfs/go-block-format v0.1.2 // indirect + github.com/ipfs/go-block-format v0.2.0 // indirect github.com/ipfs/go-ipfs-blockstore v1.3.0 // indirect github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect github.com/ipfs/go-ipfs-files v0.2.0 // indirect github.com/ipfs/go-ipfs-pq v0.0.3 // indirect github.com/ipfs/go-ipfs-util v0.0.3 // indirect - github.com/ipfs/go-ipld-format v0.5.0 // indirect + github.com/ipfs/go-ipld-format v0.6.0 // indirect github.com/ipfs/go-ipld-legacy v0.2.1 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/ipfs/go-metrics-interface v0.0.1 // indirect @@ -165,6 +165,10 @@ require ( github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect + github.com/libp2p/go-libp2p-kad-dht v0.24.4 // indirect + github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect + github.com/libp2p/go-libp2p-record v0.2.0 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.7.3 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect @@ -214,10 +218,10 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/polydawn/refmt v0.89.0 // indirect github.com/polyfloyd/go-errorlint v1.4.3 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quasilyte/go-ruleguard v0.4.0 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect @@ -264,30 +268,34 @@ require ( github.com/ultraware/whitespace v0.0.5 // indirect github.com/urfave/cli v1.22.10 // indirect github.com/uudashr/gocognit v1.0.7 // indirect + github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect + github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/xen0n/gosmopolitan v1.2.1 // indirect github.com/yagipy/maintidx v1.0.0 // indirect github.com/yeya24/promlinter v0.2.0 // indirect github.com/ykadowak/zerologlint v0.1.3 // indirect gitlab.com/bosi/decorder v0.4.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect go.tmz.dev/musttag v0.7.1 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.20.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.25.0 // indirect - golang.org/x/crypto v0.12.0 // indirect - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.14.0 // indirect + golang.org/x/net v0.15.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect - golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.13.0 // indirect + gonum.org/v1/gonum v0.13.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/test/dependencies/go.sum b/test/dependencies/go.sum index 71d07193f42..99ffc1795a7 100644 --- a/test/dependencies/go.sum +++ b/test/dependencies/go.sum @@ -252,6 +252,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -310,6 +311,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -339,8 +341,8 @@ github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0Z github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -381,8 +383,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= -github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= @@ -396,12 +398,12 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 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/boxo v0.13.1 h1:nQ5oQzcMZR3oL41REJDcTbrvDvuZh3J9ckc9+ILeRQI= -github.com/ipfs/boxo v0.13.1/go.mod h1:btrtHy0lmO1ODMECbbEY1pxNtrLilvKSYLoGQt1yYCk= +github.com/ipfs/boxo v0.14.0 h1:gwSGW3xqUbtUOdn71oqBknpBFKpQm352g3I+RkebrX0= +github.com/ipfs/boxo v0.14.0/go.mod h1:pu8HsZvuyYeYJsqtLDCoYSvy8rHj6vI3dlh8P0f83Zs= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= -github.com/ipfs/go-block-format v0.1.2 h1:GAjkfhVx1f4YTODS6Esrj1wt2HhrtwTnhEr+DyPUaJo= -github.com/ipfs/go-block-format v0.1.2/go.mod h1:mACVcrxarQKstUU3Yf/RdwbC4DzPV6++rO2a3d+a/KE= +github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= +github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= github.com/ipfs/go-blockservice v0.5.0 h1:B2mwhhhVQl2ntW2EIpaWPwSCxSuqr5fFA93Ms4bYLEY= github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= @@ -433,8 +435,8 @@ github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3 github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0= github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs= github.com/ipfs/go-ipld-cbor v0.0.6 h1:pYuWHyvSpIsOOLw4Jy7NbBkCyzLDcl64Bf/LZW7eBQ0= -github.com/ipfs/go-ipld-format v0.5.0 h1:WyEle9K96MSrvr47zZHKKcDxJ/vlpET6PSiQsAFO+Ds= -github.com/ipfs/go-ipld-format v0.5.0/go.mod h1:ImdZqJQaEouMjCvqCe0ORUS+uoBmf7Hf+EO/jh+nk3M= +github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= +github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg= github.com/ipfs/go-ipld-legacy v0.2.1 h1:mDFtrBpmU7b//LzLSypVrXsD8QxkEWxu5qVxN99/+tk= github.com/ipfs/go-ipld-legacy v0.2.1/go.mod h1:782MOUghNzMO2DER0FlBR94mllfdCJCkTtDtPM51otM= github.com/ipfs/go-libipfs v0.7.0 h1:Mi54WJTODaOL2/ZSm5loi3SwI3jI2OuFWUrQIkJ5cpM= @@ -546,7 +548,14 @@ github.com/libp2p/go-libp2p v0.31.0 h1:LFShhP8F6xthWiBBq3euxbKjZsoRajVEyBS9snfHx github.com/libp2p/go-libp2p v0.31.0/go.mod h1:W/FEK1c/t04PbRH3fA9i5oucu5YcgrG0JVoBWT1B7Eg= github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= +github.com/libp2p/go-libp2p-kad-dht v0.24.4 h1:ktNiJe7ffsJ1wX3ULpMCwXts99mPqGFSE/Qn1i8pErQ= +github.com/libp2p/go-libp2p-kad-dht v0.24.4/go.mod h1:ybWBJ5Fbvz9sSLkNtXt+2+bK0JB8+tRPvhBbRGHegRU= +github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0= +github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0= github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= +github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= +github.com/libp2p/go-libp2p-routing-helpers v0.7.3 h1:u1LGzAMVRK9Nqq5aYDVOiq/HaB93U9WWczBzGyAC5ZY= +github.com/libp2p/go-libp2p-routing-helpers v0.7.3/go.mod h1:cN4mJAD/7zfPKXBcs9ze31JGYAZgzdABEm+q/hkswb8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= @@ -707,14 +716,14 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= @@ -728,8 +737,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quasilyte/go-ruleguard v0.4.0 h1:DyM6r+TKL+xbKB4Nm7Afd1IQh9kEUKQs2pboWGKtvQo= github.com/quasilyte/go-ruleguard v0.4.0/go.mod h1:Eu76Z/R8IXtViWUIHkE3p8gdH3/PKk1eh3YGfaEof10= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= @@ -848,6 +857,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -887,9 +897,13 @@ github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMI github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s= 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-gen v0.0.0-20230126041949-52956bd4c9aa h1:EyA027ZAkuaCLoxVX4r1TZMPy1d31fM6hbfQ4OU4I5o= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= +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= github.com/xen0n/gosmopolitan v1.2.1 h1:3pttnTuFumELBRSh+KQs1zcz4fN6Zy7aB0xlnQSn1Iw= github.com/xen0n/gosmopolitan v1.2.1/go.mod h1:JsHq/Brs1o050OOdmzHeOr0N7OtlnKRAGAsElF8xBQA= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= @@ -915,13 +929,15 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.tmz.dev/musttag v0.7.1 h1:9lFmeSFnFfPuMq4IksHGomItE6NgKMNW2Nt2FPOhCfU= go.tmz.dev/musttag v0.7.1/go.mod h1:oJLkpR56EsIryktZJk/B0IroSMi37YWver47fibGh5U= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -941,8 +957,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -960,8 +976,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 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= @@ -972,8 +988,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-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 h1:jWGQJV4niP+CCmFW9ekjA9Zx8vYORzOUH2/Nl5WPuLQ= @@ -1045,6 +1061,7 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -1057,8 +1074,8 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 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= @@ -1155,16 +1172,16 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1176,8 +1193,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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= @@ -1259,13 +1276,15 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= +gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= diff --git a/test/integration/addcat_test.go b/test/integration/addcat_test.go index 2974f51fbbe..222326de21d 100644 --- a/test/integration/addcat_test.go +++ b/test/integration/addcat_test.go @@ -11,10 +11,10 @@ import ( "testing" "time" + "github.com/ipfs/boxo/bootstrap" "github.com/ipfs/boxo/files" logging "github.com/ipfs/go-log" "github.com/ipfs/kubo/core" - "github.com/ipfs/kubo/core/bootstrap" "github.com/ipfs/kubo/core/coreapi" mock "github.com/ipfs/kubo/core/mock" "github.com/ipfs/kubo/thirdparty/unit" diff --git a/test/integration/bench_cat_test.go b/test/integration/bench_cat_test.go index e95ff87dfce..d0c0a4b8983 100644 --- a/test/integration/bench_cat_test.go +++ b/test/integration/bench_cat_test.go @@ -8,9 +8,9 @@ import ( "math" "testing" + "github.com/ipfs/boxo/bootstrap" "github.com/ipfs/boxo/files" "github.com/ipfs/kubo/core" - "github.com/ipfs/kubo/core/bootstrap" "github.com/ipfs/kubo/core/coreapi" mock "github.com/ipfs/kubo/core/mock" "github.com/ipfs/kubo/thirdparty/unit" diff --git a/test/integration/pubsub_msg_seen_cache_test.go b/test/integration/pubsub_msg_seen_cache_test.go index 4194881a53b..85cc8ae9f1e 100644 --- a/test/integration/pubsub_msg_seen_cache_test.go +++ b/test/integration/pubsub_msg_seen_cache_test.go @@ -10,9 +10,9 @@ import ( "go.uber.org/fx" + "github.com/ipfs/boxo/bootstrap" "github.com/ipfs/kubo/config" "github.com/ipfs/kubo/core" - "github.com/ipfs/kubo/core/bootstrap" "github.com/ipfs/kubo/core/coreapi" libp2p2 "github.com/ipfs/kubo/core/node/libp2p" "github.com/ipfs/kubo/repo" diff --git a/test/integration/three_legged_cat_test.go b/test/integration/three_legged_cat_test.go index e8a838e1f47..fa594f1e5c2 100644 --- a/test/integration/three_legged_cat_test.go +++ b/test/integration/three_legged_cat_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - bootstrap2 "github.com/ipfs/kubo/core/bootstrap" + bootstrap2 "github.com/ipfs/boxo/bootstrap" "github.com/ipfs/kubo/core/coreapi" mock "github.com/ipfs/kubo/core/mock" "github.com/ipfs/kubo/thirdparty/unit" diff --git a/test/sharness/t0054-dag-car-import-export.sh b/test/sharness/t0054-dag-car-import-export.sh index 0482f24d92d..e277cc46687 100755 --- a/test/sharness/t0054-dag-car-import-export.sh +++ b/test/sharness/t0054-dag-car-import-export.sh @@ -178,13 +178,11 @@ test_expect_success "basic offline export of 'getting started' dag works" ' ipfs dag export "$HASH_WELCOME_DOCS" >/dev/null ' - -echo "Error: block was not found locally (offline): ipld: could not find QmYwAPJXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (currently offline, perhaps retry after attaching to the network)" > offline_fetch_error_expected test_expect_success "basic offline export of nonexistent cid" ' ! ipfs dag export QmYwAPJXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2> offline_fetch_error_actual >/dev/null ' test_expect_success "correct error" ' - test_cmp_sorted offline_fetch_error_expected offline_fetch_error_actual + test_should_contain "Error: block was not found locally (offline): ipld: could not find QmYwAPJXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" offline_fetch_error_actual ' cat >multiroot_import_json_stats_expected <expected && test_must_fail ipfs get ../.. 2>actual && - test_cmp expected actual + test_should_contain "Error: invalid path \"../..\"" actual ' test_expect_success "create small file" ' diff --git a/test/sharness/t0160-resolve.sh b/test/sharness/t0160-resolve.sh index f65b29c11b6..5ec3f99be0d 100755 --- a/test/sharness/t0160-resolve.sh +++ b/test/sharness/t0160-resolve.sh @@ -30,8 +30,11 @@ test_resolve_setup_name() { local key="$1" local ref="$2" + # we pass here --ttl=0s to ensure that it does not get cached by namesys. + # the alternative would be to wait between tests to ensure that the namesys + # cache gets purged in time, but that adds runtime time for the tests. test_expect_success "resolve: prepare $key" ' - ipfs name publish --key="$key" --allow-offline "$ref" + ipfs name publish --key="$key" --ttl=0s --allow-offline "$ref" ' } diff --git a/version.go b/version.go index 2491eeffb04..cb9d87a6100 100644 --- a/version.go +++ b/version.go @@ -11,7 +11,7 @@ import ( var CurrentCommit string // CurrentVersionNumber is the current application's version literal. -const CurrentVersionNumber = "0.23.0" +const CurrentVersionNumber = "0.24.0-rc1" const ApiVersion = "/kubo/" + CurrentVersionNumber + "/" //nolint