diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 02989e6aa..af9006adf 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,12 +31,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000..de174afc4 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,3 @@ +linters: + enable: + - stylecheck diff --git a/CHANGELOG.md b/CHANGELOG.md index f2e34c336..d3b9663c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Kubo Changelogs +- [v0.16](docs/changelogs/v0.16.md) - [v0.15](docs/changelogs/v0.15.md) - [v0.14](docs/changelogs/v0.14.md) - [v0.13](docs/changelogs/v0.13.md) diff --git a/README.md b/README.md index 54098932c..04652bf03 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,3 @@ -# kubo - -> the oldest IPFS implementation, previously known as "go-ipfs" ![kubo, an IPFS node in Go](https://ipfs.io/ipfs/bafykbzacecaesuqmivkauix25v6i6xxxsvsrtxknhgb5zak3xxsg2nb4dhs2u/ipfs.go.png) @@ -10,15 +7,18 @@ ## What is Kubo? -Kubo (go-ipfs) the earliest and most widely used implementation of IPFS. +Kubo was the first IPFS implementation and is the most widely used one today. Implementing the *Interplanetary Filesystem* - the Web3 standard and contender to replace https. Thus powered by IPLD's data models and the libp2p for network communication. Kubo is written in Go. -It includes: -- an IPFS daemon server -- extensive [command line tooling](https://docs.ipfs.tech/reference/kubo/cli/) -- an [HTTP Gateway](https://docs.ipfs.tech/reference/http/gateway/) (`/ipfs/`, `/ipns/`) for serving content to HTTP browsers -- an [HTTP RPC API](https://docs.ipfs.tech/reference/kubo/rpc/) (`/api/v0`) for controlling the daemon node +Featureset +- Runs an IPFS-Node as a network service +- [Command Line Interface](https://docs.ipfs.tech/reference/kubo/cli/) to IPFS-Nodes +- Local [Web2-to-Web3 HTTP Gateway functionality](https://github.com/ipfs/specs/tree/main/http-gateways#readme) +- HTTP RPC API (`/api/v0`) to access and control the daemon +- IPFS's internal Webgui can be used to manage the Kubo nodes -Note: [other implementations exist](https://docs.ipfs.tech/basics/ipfs-implementations/). +### Other implementations + +See [List](https://docs.ipfs.tech/basics/ipfs-implementations/) ## What is IPFS? diff --git a/cmd/ipfs/add_migrations.go b/cmd/ipfs/add_migrations.go index 95e0d10da..6d62b4d6b 100644 --- a/cmd/ipfs/add_migrations.go +++ b/cmd/ipfs/add_migrations.go @@ -56,7 +56,7 @@ func addMigrations(ctx context.Context, node *core.IpfsNode, fetcher migrations. } } default: - return errors.New("Cannot get migrations from unknown fetcher type") + return errors.New("cannot get migrations from unknown fetcher type") } } @@ -118,9 +118,9 @@ func addMigrationPaths(ctx context.Context, node *core.IpfsNode, peerInfo peer.A fmt.Printf("connected to migration peer %q\n", peerInfo) if pin { - pinApi := ipfs.Pin() + pinAPI := ipfs.Pin() for _, ipfsPath := range paths { - err := pinApi.Add(ctx, ipfsPath) + err := pinAPI.Add(ctx, ipfsPath) if err != nil { return err } diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 0178d4bf9..1bfb9d6f1 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -59,9 +59,10 @@ const ( routingOptionDHTKwd = "dht" routingOptionDHTServerKwd = "dhtserver" routingOptionNoneKwd = "none" + routingOptionCustomKwd = "custom" routingOptionDefaultKwd = "default" unencryptTransportKwd = "disable-transport-encryption" - unrestrictedApiAccessKwd = "unrestricted-api" + unrestrictedAPIAccessKwd = "unrestricted-api" writableKwd = "writable" enablePubSubKwd = "enable-pubsub-experiment" enableIPNSPubSubKwd = "enable-namesys-pubsub" @@ -173,7 +174,7 @@ Headers. cmds.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)"), cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."), cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."), - cmds.BoolOption(unrestrictedApiAccessKwd, "Allow API access to unlisted hashes"), + cmds.BoolOption(unrestrictedAPIAccessKwd, "Allow API access to unlisted hashes"), cmds.BoolOption(unencryptTransportKwd, "Disable transport encryption (for debugging protocols)"), cmds.BoolOption(enableGCKwd, "Enable automatic periodic repo garbage collection"), cmds.BoolOption(adjustFDLimitKwd, "Check and raise file descriptor limits if needed").WithDefault(true), @@ -401,7 +402,10 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment routingOption, _ := req.Options[routingOptionKwd].(string) if routingOption == routingOptionDefaultKwd { - routingOption = cfg.Routing.Type.WithDefault(routingOptionDHTKwd) + routingOption = cfg.Routing.Type + if routingOption == "" { + routingOption = routingOptionDHTKwd + } } switch routingOption { case routingOptionSupernodeKwd: @@ -414,6 +418,14 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment ncfg.Routing = libp2p.DHTServerOption case routingOptionNoneKwd: ncfg.Routing = libp2p.NilRouterOption + case routingOptionCustomKwd: + ncfg.Routing = libp2p.ConstructDelegatedRouting( + cfg.Routing.Routers, + cfg.Routing.Methods, + cfg.Identity.PeerID, + cfg.Addresses.Swarm, + cfg.Identity.PrivKey, + ) default: return fmt.Errorf("unrecognized routing option: %s", routingOption) } @@ -521,6 +533,7 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment "commit": version.CurrentCommit, }).Set(1) + // TODO(9285): make metrics more configurable // initialize metrics collector prometheus.MustRegister(&corehttp.IpfsNodeCollector{Node: node}) @@ -641,7 +654,7 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error // because this would open up the api to scripting vulnerabilities. // only the webui objects are allowed. // if you know what you're doing, go ahead and pass --unrestricted-api. - unrestricted, _ := req.Options[unrestrictedApiAccessKwd].(bool) + unrestricted, _ := req.Options[unrestrictedAPIAccessKwd].(bool) gatewayOpt := corehttp.GatewayOption(false, corehttp.WebUIPaths...) if unrestricted { gatewayOpt = corehttp.GatewayOption(true, "/ipfs", "/ipns") diff --git a/cmd/ipfs/init.go b/cmd/ipfs/init.go index b312fcb49..745ceb3e2 100644 --- a/cmd/ipfs/init.go +++ b/cmd/ipfs/init.go @@ -32,8 +32,9 @@ const ( profileOptionName = "profile" ) +// nolint var errRepoExists = errors.New(`ipfs configuration file already exists! -Reinitializing would overwrite your keys. +Reinitializing would overwrite your keys `) var initCmd = &cmds.Command{ diff --git a/cmd/ipfs/ipfs.go b/cmd/ipfs/ipfs.go index 6b30a0fc8..24aea66c7 100644 --- a/cmd/ipfs/ipfs.go +++ b/cmd/ipfs/ipfs.go @@ -6,7 +6,7 @@ import ( cmds "github.com/ipfs/go-ipfs-cmds" ) -// This is the CLI root, used for executing commands accessible to CLI clients. +// Root is the CLI root, used for executing commands accessible to CLI clients. // Some subcommands (like 'ipfs daemon' or 'ipfs init') are only accessible here, // and can't be called through the HTTP API. var Root = &cmds.Command{ diff --git a/cmd/ipfs/pinmfs_test.go b/cmd/ipfs/pinmfs_test.go index 1f0c3636a..78c7a863b 100644 --- a/cmd/ipfs/pinmfs_test.go +++ b/cmd/ipfs/pinmfs_test.go @@ -98,7 +98,7 @@ func TestPinMFSRootNodeError(t *testing.T) { } func TestPinMFSService(t *testing.T) { - cfg_invalid_interval := &config.Config{ + cfgInvalidInterval := &config.Config{ Pinning: config.Pinning{ RemoteServices: map[string]config.RemotePinningService{ "disabled": { @@ -119,7 +119,7 @@ func TestPinMFSService(t *testing.T) { }, }, } - cfg_valid_unnamed := &config.Config{ + cfgValidUnnamed := &config.Config{ Pinning: config.Pinning{ RemoteServices: map[string]config.RemotePinningService{ "valid_unnamed": { @@ -134,7 +134,7 @@ func TestPinMFSService(t *testing.T) { }, }, } - cfg_valid_named := &config.Config{ + cfgValidNamed := &config.Config{ Pinning: config.Pinning{ RemoteServices: map[string]config.RemotePinningService{ "valid_named": { @@ -149,9 +149,9 @@ func TestPinMFSService(t *testing.T) { }, }, } - testPinMFSServiceWithError(t, cfg_invalid_interval, "remote pinning service \"invalid_interval\" has invalid MFS.RepinInterval") - testPinMFSServiceWithError(t, cfg_valid_unnamed, "error while listing remote pins: empty response from remote pinning service") - testPinMFSServiceWithError(t, cfg_valid_named, "error while listing remote pins: empty response from remote pinning service") + testPinMFSServiceWithError(t, cfgInvalidInterval, "remote pinning service \"invalid_interval\" has invalid MFS.RepinInterval") + testPinMFSServiceWithError(t, cfgValidUnnamed, "error while listing remote pins: empty response from remote pinning service") + testPinMFSServiceWithError(t, cfgValidNamed, "error while listing remote pins: empty response from remote pinning service") } func testPinMFSServiceWithError(t *testing.T, cfg *config.Config, expectedErrorPrefix string) { diff --git a/config/dns.go b/config/dns.go index b0f7b2710..444d99088 100644 --- a/config/dns.go +++ b/config/dns.go @@ -9,7 +9,7 @@ type DNS struct { // https://en.wikipedia.org/wiki/DNS_over_HTTPS // // Example: - // - Custom resolver for ENS: `eth.` → `https://eth.link/dns-query` + // - Custom resolver for ENS: `eth.` → `https://dns.eth.limo/dns-query` // - Override the default OS resolver: `.` → `https://doh.applied-privacy.net/query` Resolvers map[string]string // MaxCacheTTL is the maximum duration DNS entries are valid in the cache. diff --git a/config/experiments.go b/config/experiments.go index a576a5b61..7ad87c853 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -6,7 +6,7 @@ type Experiments struct { ShardingEnabled bool `json:",omitempty"` // deprecated by autosharding: https://github.com/ipfs/kubo/pull/8527 GraphsyncEnabled bool Libp2pStreamMounting bool - P2pHttpProxy bool + P2pHttpProxy bool //nolint StrategicProviding bool AcceleratedDHTClient bool } diff --git a/config/gateway.go b/config/gateway.go index 71b57dca6..8b8c65d1d 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -1,5 +1,7 @@ package config +const DefaultInlineDNSLink = false + type GatewaySpec struct { // Paths is explicit list of path prefixes that should be handled by // this gateway. Example: `["/ipfs", "/ipns", "/api"]` @@ -18,6 +20,11 @@ type GatewaySpec struct { // NoDNSLink configures this gateway to _not_ resolve DNSLink for the FQDN // provided in `Host` HTTP header. NoDNSLink bool + + // InlineDNSLink configures this gateway to always inline DNSLink names + // (FQDN) into a single DNS label in order to interop with wildcard TLS certs + // and Origin per CID isolation provided by rules like https://publicsuffix.org + InlineDNSLink Flag } // Gateway contains options for the HTTP gateway server. diff --git a/config/init.go b/config/init.go index 6bc7a1785..cc2351f1f 100644 --- a/config/init.go +++ b/config/init.go @@ -48,7 +48,9 @@ func InitWithIdentity(identity Identity) (*Config, error) { }, Routing: Routing{ - Type: NewOptionalString("dht"), + Type: "dht", + Methods: nil, + Routers: nil, }, // setup the node mount points. diff --git a/config/profile.go b/config/profile.go index 8252d1ab9..cbc7c9764 100644 --- a/config/profile.go +++ b/config/profile.go @@ -174,7 +174,7 @@ functionality - performance of content discovery and data fetching may be degraded. `, Transform: func(c *Config) error { - c.Routing.Type = NewOptionalString("dhtclient") + c.Routing.Type = "dhtclient" c.AutoNAT.ServiceMode = AutoNATServiceDisabled c.Reprovider.Interval = "0" diff --git a/config/routing.go b/config/routing.go index 4a96589da..cecba7a5e 100644 --- a/config/routing.go +++ b/config/routing.go @@ -1,28 +1,101 @@ package config +import ( + "encoding/json" + "fmt" +) + // Routing defines configuration options for libp2p routing type Routing struct { // Type sets default daemon routing mode. // - // Can be one of "dht", "dhtclient", "dhtserver", "none", or unset. - Type *OptionalString `json:",omitempty"` + // Can be one of "dht", "dhtclient", "dhtserver", "none", or "custom". + // When "custom" is set, you can specify a list of Routers. + Type string - Routers map[string]Router + Routers Routers + + Methods Methods } type Router struct { - // Currenly only supported Type is "reframe". + // Currenly supported Types are "reframe", "dht", "parallel", "sequential". // Reframe type allows to add other resolvers using the Reframe spec: // https://github.com/ipfs/specs/tree/main/reframe // In the future we will support "dht" and other Types here. - Type string - - Enabled Flag `json:",omitempty"` + Type RouterType // Parameters are extra configuration that this router might need. // A common one for reframe router is "Endpoint". - Parameters map[string]string + Parameters interface{} +} + +type Routers map[string]RouterParser +type Methods map[MethodName]Method + +func (m Methods) Check() error { + + // Check supported methods + for _, mn := range MethodNameList { + _, ok := m[mn] + if !ok { + return fmt.Errorf("method name %q is missing from Routing.Methods config param", mn) + } + } + + // Check unsupported methods + for k := range m { + seen := false + for _, mn := range MethodNameList { + if mn == k { + seen = true + break + } + } + + if seen { + continue + } + + return fmt.Errorf("method name %q is not a supported method on Routing.Methods config param", k) + } + + return nil +} + +type RouterParser struct { + Router +} + +func (r *RouterParser) UnmarshalJSON(b []byte) error { + out := Router{} + out.Parameters = &json.RawMessage{} + if err := json.Unmarshal(b, &out); err != nil { + return err + } + raw := out.Parameters.(*json.RawMessage) + + var p interface{} + switch out.Type { + case RouterTypeReframe: + p = &ReframeRouterParams{} + case RouterTypeDHT: + p = &DHTRouterParams{} + case RouterTypeSequential: + p = &ComposableRouterParams{} + case RouterTypeParallel: + p = &ComposableRouterParams{} + } + + if err := json.Unmarshal(*raw, &p); err != nil { + return err + } + + r.Router.Type = out.Type + r.Router.Parameters = p + + return nil } // Type is the routing type. @@ -30,15 +103,56 @@ type Router struct { type RouterType string const ( - RouterTypeReframe RouterType = "reframe" + RouterTypeReframe RouterType = "reframe" + RouterTypeDHT RouterType = "dht" + RouterTypeSequential RouterType = "sequential" + RouterTypeParallel RouterType = "parallel" ) -type RouterParam string +type DHTMode string const ( - // RouterParamEndpoint is the URL where the routing implementation will point to get the information. - // Usually used for reframe Routers. - RouterParamEndpoint RouterParam = "Endpoint" - - RouterParamPriority RouterParam = "Priority" + DHTModeServer DHTMode = "server" + DHTModeClient DHTMode = "client" + DHTModeAuto DHTMode = "auto" ) + +type MethodName string + +const ( + MethodNameProvide MethodName = "provide" + MethodNameFindProviders MethodName = "find-providers" + MethodNameFindPeers MethodName = "find-peers" + MethodNameGetIPNS MethodName = "get-ipns" + MethodNamePutIPNS MethodName = "put-ipns" +) + +var MethodNameList = []MethodName{MethodNameProvide, MethodNameFindPeers, MethodNameFindProviders, MethodNameGetIPNS, MethodNamePutIPNS} + +type ReframeRouterParams struct { + // Endpoint is the URL where the routing implementation will point to get the information. + // Usually used for reframe Routers. + Endpoint string +} + +type DHTRouterParams struct { + Mode DHTMode + AcceleratedDHTClient bool `json:",omitempty"` + PublicIPNetwork bool +} + +type ComposableRouterParams struct { + Routers []ConfigRouter + Timeout *OptionalDuration `json:",omitempty"` +} + +type ConfigRouter struct { + RouterName string + Timeout Duration + IgnoreErrors bool + ExecuteAfter *OptionalDuration `json:",omitempty"` +} + +type Method struct { + RouterName string +} diff --git a/config/routing_test.go b/config/routing_test.go new file mode 100644 index 000000000..013e285a5 --- /dev/null +++ b/config/routing_test.go @@ -0,0 +1,195 @@ +package config + +import ( + "encoding/json" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestRouterParameters(t *testing.T) { + require := require.New(t) + sec := time.Second + min := time.Minute + r := Routing{ + Type: "custom", + Routers: map[string]RouterParser{ + "router-dht": {Router{ + Type: RouterTypeDHT, + Parameters: DHTRouterParams{ + Mode: "auto", + AcceleratedDHTClient: true, + PublicIPNetwork: false, + }, + }}, + "router-reframe": {Router{ + Type: RouterTypeReframe, + Parameters: ReframeRouterParams{ + Endpoint: "reframe-endpoint", + }, + }}, + "router-parallel": {Router{ + Type: RouterTypeParallel, + Parameters: ComposableRouterParams{ + Routers: []ConfigRouter{ + { + RouterName: "router-dht", + Timeout: Duration{10 * time.Second}, + IgnoreErrors: true, + }, + { + RouterName: "router-reframe", + Timeout: Duration{10 * time.Second}, + IgnoreErrors: false, + ExecuteAfter: &OptionalDuration{&sec}, + }, + }, + Timeout: &OptionalDuration{&min}, + }}, + }, + "router-sequential": {Router{ + Type: RouterTypeSequential, + Parameters: ComposableRouterParams{ + Routers: []ConfigRouter{ + { + RouterName: "router-dht", + Timeout: Duration{10 * time.Second}, + IgnoreErrors: true, + }, + { + RouterName: "router-reframe", + Timeout: Duration{10 * time.Second}, + IgnoreErrors: false, + }, + }, + Timeout: &OptionalDuration{&min}, + }}, + }, + }, + Methods: Methods{ + MethodNameFindPeers: { + RouterName: "router-reframe", + }, + MethodNameFindProviders: { + RouterName: "router-dht", + }, + MethodNameGetIPNS: { + RouterName: "router-sequential", + }, + MethodNameProvide: { + RouterName: "router-parallel", + }, + MethodNamePutIPNS: { + RouterName: "router-parallel", + }, + }, + } + + out, err := json.Marshal(r) + require.NoError(err) + + r2 := &Routing{} + + err = json.Unmarshal(out, r2) + require.NoError(err) + + require.Equal(5, len(r2.Methods)) + + dhtp := r2.Routers["router-dht"].Parameters + require.IsType(&DHTRouterParams{}, dhtp) + + rp := r2.Routers["router-reframe"].Parameters + require.IsType(&ReframeRouterParams{}, rp) + + sp := r2.Routers["router-sequential"].Parameters + require.IsType(&ComposableRouterParams{}, sp) + + pp := r2.Routers["router-parallel"].Parameters + require.IsType(&ComposableRouterParams{}, pp) +} + +func TestRouterMissingParameters(t *testing.T) { + require := require.New(t) + + r := Routing{ + Type: "custom", + Routers: map[string]RouterParser{ + "router-wrong-reframe": {Router{ + Type: RouterTypeReframe, + Parameters: DHTRouterParams{ + Mode: "auto", + AcceleratedDHTClient: true, + PublicIPNetwork: false, + }, + }}, + }, + Methods: Methods{ + MethodNameFindPeers: { + RouterName: "router-wrong-reframe", + }, + MethodNameFindProviders: { + RouterName: "router-wrong-reframe", + }, + MethodNameGetIPNS: { + RouterName: "router-wrong-reframe", + }, + MethodNameProvide: { + RouterName: "router-wrong-reframe", + }, + MethodNamePutIPNS: { + RouterName: "router-wrong-reframe", + }, + }, + } + + out, err := json.Marshal(r) + require.NoError(err) + + r2 := &Routing{} + + err = json.Unmarshal(out, r2) + require.NoError(err) + require.Empty(r2.Routers["router-wrong-reframe"].Parameters.(*ReframeRouterParams).Endpoint) +} + +func TestMethods(t *testing.T) { + require := require.New(t) + + methodsOK := Methods{ + MethodNameFindPeers: { + RouterName: "router-wrong-reframe", + }, + MethodNameFindProviders: { + RouterName: "router-wrong-reframe", + }, + MethodNameGetIPNS: { + RouterName: "router-wrong-reframe", + }, + MethodNameProvide: { + RouterName: "router-wrong-reframe", + }, + MethodNamePutIPNS: { + RouterName: "router-wrong-reframe", + }, + } + + require.NoError(methodsOK.Check()) + + methodsMissing := Methods{ + MethodNameFindPeers: { + RouterName: "router-wrong-reframe", + }, + MethodNameGetIPNS: { + RouterName: "router-wrong-reframe", + }, + MethodNameProvide: { + RouterName: "router-wrong-reframe", + }, + MethodNamePutIPNS: { + RouterName: "router-wrong-reframe", + }, + } + + require.Error(methodsMissing.Check()) +} diff --git a/config/swarm.go b/config/swarm.go index 93163c479..01181f36e 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -104,6 +104,8 @@ type Transports struct { TCP Flag `json:",omitempty"` Websocket Flag `json:",omitempty"` Relay Flag `json:",omitempty"` + // except WebTransport which is experimental and optin. + WebTransport Flag `json:",omitempty"` } // Security specifies the transports used to encrypt insecure network diff --git a/config/types.go b/config/types.go index f27c5fa13..e3f61546b 100644 --- a/config/types.go +++ b/config/types.go @@ -262,6 +262,38 @@ func (d OptionalDuration) String() string { var _ json.Unmarshaler = (*OptionalDuration)(nil) var _ json.Marshaler = (*OptionalDuration)(nil) +type Duration struct { + time.Duration +} + +func (d Duration) MarshalJSON() ([]byte, error) { + return json.Marshal(d.String()) +} + +func (d *Duration) UnmarshalJSON(b []byte) error { + var v interface{} + if err := json.Unmarshal(b, &v); err != nil { + return err + } + switch value := v.(type) { + case float64: + d.Duration = time.Duration(value) + return nil + case string: + var err error + d.Duration, err = time.ParseDuration(value) + if err != nil { + return err + } + return nil + default: + return fmt.Errorf("unable to parse duration, expected a duration string or a float, but got %T", v) + } +} + +var _ json.Unmarshaler = (*Duration)(nil) +var _ json.Marshaler = (*Duration)(nil) + // OptionalInteger represents an integer that has a default value // // When encoded in json, Default is encoded as "null" diff --git a/core/commands/add.go b/core/commands/add.go index fb8ee8a31..12a38aaeb 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -13,6 +13,8 @@ import ( "github.com/cheggaaa/pb" cmds "github.com/ipfs/go-ipfs-cmds" files "github.com/ipfs/go-ipfs-files" + ipld "github.com/ipfs/go-ipld-format" + mfs "github.com/ipfs/go-mfs" coreiface "github.com/ipfs/interface-go-ipfs-core" "github.com/ipfs/interface-go-ipfs-core/options" mh "github.com/multiformats/go-multihash" @@ -45,6 +47,7 @@ const ( hashOptionName = "hash" inlineOptionName = "inline" inlineLimitOptionName = "inline-limit" + toFilesOptionName = "to-files" ) const adderOutChanSize = 8 @@ -79,6 +82,20 @@ You can now refer to the added file in a gateway, like so: /ipfs/QmaG4FuMqEBnQNn3C8XJ5bpW8kLs7zq2ZXgHptJHbKDDVx/example.jpg +Files imported with 'ipfs add' are protected from GC (implicit '--pin=true'), +but it is up to you to remember the returned CID to get the data back later. + +Passing '--to-files' creates a reference in Files API (MFS), making it easier +to find it in the future: + + > ipfs files mkdir -p /myfs/dir + > ipfs add example.jpg --to-files /myfs/dir/ + > ipfs files ls /myfs/dir/ + example.jpg + +See 'ipfs files --help' to learn more about using MFS +for keeping track of added files and directories. + The chunker option, '-s', specifies the chunking strategy that dictates how to break files into blocks. Blocks with same content can be deduplicated. Different chunking strategies will produce different @@ -138,7 +155,6 @@ See 'dag export' and 'dag import' for more information. cmds.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."), cmds.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."), cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm, size-[bytes], rabin-[min]-[avg]-[max] or buzhash").WithDefault("size-262144"), - cmds.BoolOption(pinOptionName, "Pin this object when adding.").WithDefault(true), cmds.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes."), cmds.BoolOption(noCopyOptionName, "Add the file using filestore. Implies raw-leaves. (experimental)"), cmds.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. (experimental)"), @@ -146,6 +162,8 @@ See 'dag export' and 'dag import' for more information. cmds.StringOption(hashOptionName, "Hash function to use. Implies CIDv1 if not sha2-256. (experimental)").WithDefault("sha2-256"), cmds.BoolOption(inlineOptionName, "Inline small blocks into CIDs. (experimental)"), cmds.IntOption(inlineLimitOptionName, "Maximum block size to inline. (experimental)").WithDefault(32), + cmds.BoolOption(pinOptionName, "Pin locally to protect added files from garbage collection.").WithDefault(true), + cmds.StringOption(toFilesOptionName, "Add reference to Files API (MFS) at the provided path."), }, PreRun: func(req *cmds.Request, env cmds.Environment) error { quiet, _ := req.Options[quietOptionName].(bool) @@ -186,10 +204,14 @@ See 'dag export' and 'dag import' for more information. hashFunStr, _ := req.Options[hashOptionName].(string) inline, _ := req.Options[inlineOptionName].(bool) inlineLimit, _ := req.Options[inlineLimitOptionName].(int) + toFilesStr, toFilesSet := req.Options[toFilesOptionName].(string) hashFunCode, ok := mh.Names[strings.ToLower(hashFunStr)] if !ok { - return fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr)) + return fmt.Errorf("unrecognized hash function: %q", strings.ToLower(hashFunStr)) + } + if _, err := mh.GetHasher(hashFunCode); err != nil { + return err } enc, err := cmdenv.GetCidEncoder(req) @@ -235,7 +257,12 @@ See 'dag export' and 'dag import' for more information. opts = append(opts, nil) // events option placeholder + ipfsNode, err := cmdenv.GetNode(env) + if err != nil { + return err + } var added int + var fileAddedToMFS bool addit := toadd.Entries() for addit.Next() { _, dir := addit.Node().(files.Directory) @@ -246,7 +273,65 @@ See 'dag export' and 'dag import' for more information. go func() { var err error defer close(events) - _, err = api.Unixfs().Add(req.Context, addit.Node(), opts...) + pathAdded, err := api.Unixfs().Add(req.Context, addit.Node(), opts...) + if err != nil { + errCh <- err + return + } + + // creating MFS pointers when optional --to-files is set + if toFilesSet { + if toFilesStr == "" { + toFilesStr = "/" + } + toFilesDst, err := checkPath(toFilesStr) + if err != nil { + errCh <- fmt.Errorf("%s: %w", toFilesOptionName, err) + return + } + dstAsDir := toFilesDst[len(toFilesDst)-1] == '/' + + if dstAsDir { + mfsNode, err := mfs.Lookup(ipfsNode.FilesRoot, toFilesDst) + // confirm dst exists + if err != nil { + errCh <- fmt.Errorf("%s: MFS destination directory %q does not exist: %w", toFilesOptionName, toFilesDst, err) + return + } + // confirm dst is a dir + if mfsNode.Type() != mfs.TDir { + errCh <- fmt.Errorf("%s: MFS destination %q is not a directory", toFilesOptionName, toFilesDst) + return + } + // if MFS destination is a dir, append filename to the dir path + toFilesDst += path.Base(addit.Name()) + } + + // error if we try to overwrite a preexisting file destination + if fileAddedToMFS && !dstAsDir { + errCh <- fmt.Errorf("%s: MFS destination is a file: only one entry can be copied to %q", toFilesOptionName, toFilesDst) + return + } + + _, err = mfs.Lookup(ipfsNode.FilesRoot, path.Dir(toFilesDst)) + if err != nil { + errCh <- fmt.Errorf("%s: MFS destination parent %q %q does not exist: %w", toFilesOptionName, toFilesDst, path.Dir(toFilesDst), err) + return + } + + var nodeAdded ipld.Node + nodeAdded, err = api.Dag().Get(req.Context, pathAdded.Cid()) + if err != nil { + errCh <- err + return + } + err = mfs.PutNode(ipfsNode.FilesRoot, toFilesDst, nodeAdded) + if err != nil { + errCh <- fmt.Errorf("%s: cannot put node in path %q: %w", toFilesOptionName, toFilesDst, err) + return + } + fileAddedToMFS = true + } errCh <- err }() diff --git a/core/commands/cid.go b/core/commands/cid.go index 0cf0e9dc0..a6406a3e0 100644 --- a/core/commands/cid.go +++ b/core/commands/cid.go @@ -13,7 +13,6 @@ import ( verifcid "github.com/ipfs/go-verifcid" ipldmulticodec "github.com/ipld/go-ipld-prime/multicodec" mbase "github.com/multiformats/go-multibase" - "github.com/multiformats/go-multicodec" mc "github.com/multiformats/go-multicodec" mhash "github.com/multiformats/go-multihash" ) @@ -71,7 +70,7 @@ The optional format string is a printf style format string: opts.fmtStr = fmtStr if codecStr != "" { - var codec multicodec.Code + var codec mc.Code err := codec.Set(codecStr) if err != nil { return err diff --git a/core/commands/cmdenv/env.go b/core/commands/cmdenv/env.go index 48cbf2b03..2c5845890 100644 --- a/core/commands/cmdenv/env.go +++ b/core/commands/cmdenv/env.go @@ -27,7 +27,7 @@ func GetNode(env interface{}) (*core.IpfsNode, error) { } // GetApi extracts CoreAPI instance from the environment. -func GetApi(env cmds.Environment, req *cmds.Request) (coreiface.CoreAPI, error) { +func GetApi(env cmds.Environment, req *cmds.Request) (coreiface.CoreAPI, error) { //nolint ctx, ok := env.(*commands.Context) if !ok { return nil, fmt.Errorf("expected env to be of type %T, got %T", ctx, env) diff --git a/core/commands/dag/dag.go b/core/commands/dag/dag.go index 77c9ee4b5..df7762c00 100644 --- a/core/commands/dag/dag.go +++ b/core/commands/dag/dag.go @@ -223,7 +223,7 @@ Specification of CAR formats: https://ipld.io/specs/transport/car/ // event should have only one of `Root` or `Stats` set, not both if event.Root == nil { if event.Stats == nil { - return fmt.Errorf("Unexpected message from DAG import") + return fmt.Errorf("unexpected message from DAG import") } stats, _ := req.Options[statsOptionName].(bool) if stats { @@ -233,7 +233,7 @@ Specification of CAR formats: https://ipld.io/specs/transport/car/ } if event.Stats != nil { - return fmt.Errorf("Unexpected message from DAG import") + return fmt.Errorf("unexpected message from DAG import") } enc, err := cmdenv.GetLowLevelCidEncoder(req) diff --git a/core/commands/dag/export.go b/core/commands/dag/export.go index 14e982bcc..e9d120e87 100644 --- a/core/commands/dag/export.go +++ b/core/commands/dag/export.go @@ -85,7 +85,7 @@ func finishCLIExport(res cmds.Response, re cmds.ResponseEmitter) error { if !specified { // default based on TTY availability errStat, _ := os.Stderr.Stat() - if 0 != (errStat.Mode() & os.ModeCharDevice) { + if (errStat.Mode() & os.ModeCharDevice) != 0 { showProgress = true } } else if val.(bool) { diff --git a/core/commands/files.go b/core/commands/files.go index 95432ef61..e48abba28 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -581,7 +581,7 @@ const ( var filesReadCmd = &cmds.Command{ Helptext: cmds.HelpText{ - Tagline: "Read a file in a given MFS.", + Tagline: "Read a file from MFS.", ShortDescription: ` Read a specified number of bytes from a file at a given offset. By default, it will read the entire file similar to the Unix cat. @@ -724,11 +724,16 @@ const ( var filesWriteCmd = &cmds.Command{ Helptext: cmds.HelpText{ - Tagline: "Write to a mutable file in a given filesystem.", + Tagline: "Append to (modify) a file in MFS.", ShortDescription: ` -Write data to a file in a given filesystem. This command allows you to specify -a beginning offset to write to. The entire length of the input will be -written. +A low-level MFS command that allows you to append data to a file. If you want +to add a file without modifying an existing one, use 'ipfs add --to-files' +instead. +`, + LongDescription: ` +A low-level MFS command that allows you to append data at the end of a file, or +specify a beginning offset within a file to write to. The entire length of the +input will be written. If the '--create' option is specified, the file will be created if it does not exist. Nonexistent intermediate directories will not be created unless the @@ -755,6 +760,22 @@ WARNING: Usage of the '--flush=false' option does not guarantee data durability until the tree has been flushed. This can be accomplished by running 'ipfs files stat' on the file or any of its ancestors. + +WARNING: + +The CID produced by 'files write' will be different from 'ipfs add' because +'ipfs file write' creates a trickle-dag optimized for append-only operations +See '--trickle' in 'ipfs add --help' for more information. + +If you want to add a file without modifying an existing one, +use 'ipfs add' with '--to-files': + + > ipfs files mkdir -p /myfs/dir + > ipfs add example.jpg --to-files /myfs/dir/ + > ipfs files ls /myfs/dir/ + example.jpg + +See '--to-files' in 'ipfs add --help' for more information. `, }, Arguments: []cmds.Argument{ @@ -1019,7 +1040,7 @@ func updatePath(rt *mfs.Root, pth string, builder cid.Builder) error { var filesRmCmd = &cmds.Command{ Helptext: cmds.HelpText{ - Tagline: "Remove a file.", + Tagline: "Remove a file from MFS.", ShortDescription: ` Remove files or directories. diff --git a/core/commands/id.go b/core/commands/id.go index 444c32559..887f93efe 100644 --- a/core/commands/id.go +++ b/core/commands/id.go @@ -23,9 +23,9 @@ import ( identify "github.com/libp2p/go-libp2p/p2p/protocol/identify" ) -const offlineIdErrorMessage = "'ipfs id' cannot query information on remote peers without a running daemon; if you only want to convert --peerid-base, pass --offline option." +const offlineIDErrorMessage = "'ipfs id' cannot query information on remote peers without a running daemon; if you only want to convert --peerid-base, pass --offline option" -type IdOutput struct { +type IdOutput struct { //nolint ID string PublicKey string Addresses []string @@ -52,6 +52,7 @@ If no peer is specified, prints out information for local peers. : Protocol version. : Public key. : Addresses (newline delimited). +: Libp2p Protocol registrations (newline delimited). EXAMPLE: @@ -97,7 +98,7 @@ EXAMPLE: offline, _ := req.Options[OfflineOption].(bool) if !offline && !n.IsOnline { - return errors.New(offlineIdErrorMessage) + return errors.New(offlineIDErrorMessage) } if !offline { @@ -106,7 +107,7 @@ EXAMPLE: switch err { case nil: case kb.ErrLookupFailure: - return errors.New(offlineIdErrorMessage) + return errors.New(offlineIDErrorMessage) default: return err } @@ -217,7 +218,7 @@ func printSelf(keyEnc ke.KeyEncoder, node *core.IpfsNode) (interface{}, error) { info.Protocols = node.PeerHost.Mux().Protocols() sort.Strings(info.Protocols) } - info.ProtocolVersion = identify.LibP2PVersion + info.ProtocolVersion = identify.DefaultProtocolVersion info.AgentVersion = version.GetUserAgentVersion() return info, nil } diff --git a/core/commands/keystore.go b/core/commands/keystore.go index e931c38ea..f530d5eda 100644 --- a/core/commands/keystore.go +++ b/core/commands/keystore.go @@ -56,7 +56,7 @@ publish'. type KeyOutput struct { Name string - Id string + Id string //nolint } type KeyOutputList struct { @@ -67,7 +67,7 @@ type KeyOutputList struct { type KeyRenameOutput struct { Was string Now string - Id string + Id string //nolint Overwrite bool } diff --git a/core/commands/multibase.go b/core/commands/multibase.go index be8d613f2..d985aebf0 100644 --- a/core/commands/multibase.go +++ b/core/commands/multibase.go @@ -105,11 +105,11 @@ This command expects multibase inside of a file or via stdin: if err != nil { return fmt.Errorf("failed to access file: %w", err) } - encoded_data, err := io.ReadAll(file) + encodedData, err := io.ReadAll(file) if err != nil { return fmt.Errorf("failed to read file contents: %w", err) } - _, data, err := mbase.Decode(string(encoded_data)) + _, data, err := mbase.Decode(string(encodedData)) if err != nil { return fmt.Errorf("failed to decode multibase: %w", err) } @@ -156,11 +156,11 @@ but one can customize used base with -b: if err != nil { return fmt.Errorf("failed to access file: %w", err) } - encoded_data, err := io.ReadAll(file) + encodedData, err := io.ReadAll(file) if err != nil { return fmt.Errorf("failed to read file contents: %w", err) } - _, data, err := mbase.Decode(string(encoded_data)) + _, data, err := mbase.Decode(string(encodedData)) if err != nil { return fmt.Errorf("failed to decode multibase: %w", err) } diff --git a/core/commands/pin/remotepin.go b/core/commands/pin/remotepin.go index 49db55147..ae04be607 100644 --- a/core/commands/pin/remotepin.go +++ b/core/commands/pin/remotepin.go @@ -214,27 +214,27 @@ NOTE: a comma-separated notation is supported in CLI for convenience: // Block unless --background=true is passed if !req.Options[pinBackgroundOptionName].(bool) { - requestId := ps.GetRequestId() + requestID := ps.GetRequestId() for { - ps, err = c.GetStatusByID(ctx, requestId) + ps, err = c.GetStatusByID(ctx, requestID) if err != nil { - return fmt.Errorf("failed to check pin status for requestid=%q due to error: %v", requestId, err) + return fmt.Errorf("failed to check pin status for requestid=%q due to error: %v", requestID, err) } - if ps.GetRequestId() != requestId { - return fmt.Errorf("failed to check pin status for requestid=%q, remote service sent unexpected requestid=%q", requestId, ps.GetRequestId()) + if ps.GetRequestId() != requestID { + return fmt.Errorf("failed to check pin status for requestid=%q, remote service sent unexpected requestid=%q", requestID, ps.GetRequestId()) } s := ps.GetStatus() if s == pinclient.StatusPinned { break } if s == pinclient.StatusFailed { - return fmt.Errorf("remote service failed to pin requestid=%q", requestId) + return fmt.Errorf("remote service failed to pin requestid=%q", requestID) } tmr := time.NewTimer(time.Second / 2) select { case <-tmr.C: case <-ctx.Done(): - return fmt.Errorf("waiting for pin interrupted, requestid=%q remains on remote service", requestId) + return fmt.Errorf("waiting for pin interrupted, requestid=%q remains on remote service", requestID) } } } @@ -665,8 +665,8 @@ TIP: pass '--enc=json' for more useful JSON output. type ServiceDetails struct { Service string - ApiEndpoint string - Stat *Stat `json:",omitempty"` // present only when --stat not passed + ApiEndpoint string //nolint + Stat *Stat `json:",omitempty"` // present only when --stat not passed } type Stat struct { diff --git a/core/commands/root.go b/core/commands/root.go index 8a14b1c1a..cfa2708e6 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -25,7 +25,7 @@ const ( DebugOption = "debug" LocalOption = "local" // DEPRECATED: use OfflineOption OfflineOption = "offline" - ApiOption = "api" + ApiOption = "api" //nolint ) var Root = &cmds.Command{ @@ -118,7 +118,6 @@ The CLI will exit with one of the following values: }, } -// commandsDaemonCmd is the "ipfs commands" command for daemon var CommandsDaemonCmd = CommandsCmd(Root) var rootSubcommands = map[string]*cmds.Command{ diff --git a/core/commands/stat.go b/core/commands/stat.go index 0c4331fd4..a09c70ea1 100644 --- a/core/commands/stat.go +++ b/core/commands/stat.go @@ -132,8 +132,8 @@ Example: return err } } else if tfound { - protoId := protocol.ID(tstr) - stats := nd.Reporter.GetBandwidthForProtocol(protoId) + protoID := protocol.ID(tstr) + stats := nd.Reporter.GetBandwidthForProtocol(protoID) if err := res.Emit(&stats); err != nil { return err } diff --git a/core/commands/swarm.go b/core/commands/swarm.go index a070291d0..eb648a3c2 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -336,7 +336,7 @@ The output of this command is JSON. } if node.ResourceManager == nil { - return libp2p.NoResourceMgrError + return libp2p.ErrNoResourceMgr } if len(req.Arguments) != 1 { @@ -394,7 +394,7 @@ Changes made via command line are persisted in the Swarm.ResourceMgr.Limits fiel } if node.ResourceManager == nil { - return libp2p.NoResourceMgrError + return libp2p.ErrNoResourceMgr } scope := req.Arguments[0] diff --git a/core/core.go b/core/core.go index 17ccc088e..9e515b816 100644 --- a/core/core.go +++ b/core/core.go @@ -87,18 +87,18 @@ type IpfsNode struct { 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.TieredRouter `optional:"true"` // the routing system. recommend ipfs-dht - DNSResolver *madns.Resolver // the DNS 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 + 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/core_test.go b/core/core_test.go index 71de31de6..488eb8421 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -85,18 +85,18 @@ var errNotSupported = errors.New("method not supported") func TestDelegatedRoutingSingle(t *testing.T) { require := require.New(t) - pId1, priv1, err := GeneratePeerID() + pID1, priv1, err := GeneratePeerID() require.NoError(err) - pId2, _, err := GeneratePeerID() + pID2, _, err := GeneratePeerID() require.NoError(err) - theID := path.Join("/ipns", string(pId1)) - theErrorID := path.Join("/ipns", string(pId2)) + theID := path.Join("/ipns", string(pID1)) + theErrorID := path.Join("/ipns", string(pID2)) d := &delegatedRoutingService{ - goodPeerID: pId1, - badPeerID: pId2, + goodPeerID: pID1, + badPeerID: pID2, pk1: priv1, } @@ -117,25 +117,23 @@ func TestDelegatedRoutingSingle(t *testing.T) { err = n.Routing.PutValue(ctx, theID, v) require.NoError(err) - err = n.Routing.PutValue(ctx, theErrorID, v) - require.Error(err) } func TestDelegatedRoutingMulti(t *testing.T) { require := require.New(t) - pId1, priv1, err := GeneratePeerID() + pID1, priv1, err := GeneratePeerID() require.NoError(err) - pId2, priv2, err := GeneratePeerID() + pID2, priv2, err := GeneratePeerID() require.NoError(err) - theID1 := path.Join("/ipns", string(pId1)) - theID2 := path.Join("/ipns", string(pId2)) + theID1 := path.Join("/ipns", string(pID1)) + theID2 := path.Join("/ipns", string(pID2)) d1 := &delegatedRoutingService{ - goodPeerID: pId1, - badPeerID: pId2, + goodPeerID: pID1, + badPeerID: pID2, pk1: priv1, serviceID: 1, } @@ -143,8 +141,8 @@ func TestDelegatedRoutingMulti(t *testing.T) { url1 := StartRoutingServer(t, d1) d2 := &delegatedRoutingService{ - goodPeerID: pId2, - badPeerID: pId1, + goodPeerID: pID2, + badPeerID: pID1, pk1: priv2, serviceID: 2, } @@ -164,12 +162,6 @@ func TestDelegatedRoutingMulti(t *testing.T) { require.NoError(err) require.NotNil(v) require.Contains(string(v), "RECORD FROM SERVICE 2") - - err = n.Routing.PutValue(ctx, theID1, v) - require.Error(err) - - err = n.Routing.PutValue(ctx, theID2, v) - require.Error(err) } func StartRoutingServer(t *testing.T, d drs.DelegatedRoutingService) string { @@ -187,16 +179,41 @@ func StartRoutingServer(t *testing.T, d drs.DelegatedRoutingService) string { func GetNode(t *testing.T, reframeURLs ...string) *IpfsNode { t.Helper() - routers := make(map[string]config.Router) + routers := make(config.Routers) + var routerNames []string for i, ru := range reframeURLs { - routers[fmt.Sprintf("reframe-%d", i)] = config.Router{ - Type: string(config.RouterTypeReframe), - Parameters: map[string]string{ - string(config.RouterParamEndpoint): ru, - }, - } + rn := fmt.Sprintf("reframe-%d", i) + routerNames = append(routerNames, rn) + routers[rn] = + config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeReframe, + Parameters: &config.ReframeRouterParams{ + Endpoint: ru, + }, + }, + } } + var crs []config.ConfigRouter + for _, rn := range routerNames { + crs = append(crs, config.ConfigRouter{ + RouterName: rn, + IgnoreErrors: true, + Timeout: config.Duration{Duration: time.Minute}, + }) + } + + const parallelRouterName = "parallel-router" + + routers[parallelRouterName] = config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeParallel, + Parameters: &config.ComposableRouterParams{ + Routers: crs, + }, + }, + } cfg := config.Config{ Identity: testIdentity, Addresses: config.Addresses{ @@ -204,8 +221,25 @@ func GetNode(t *testing.T, reframeURLs ...string) *IpfsNode { API: []string{"/ip4/127.0.0.1/tcp/0"}, }, Routing: config.Routing{ - Type: config.NewOptionalString("none"), + Type: "custom", Routers: routers, + Methods: config.Methods{ + config.MethodNameFindPeers: config.Method{ + RouterName: parallelRouterName, + }, + config.MethodNameFindProviders: config.Method{ + RouterName: parallelRouterName, + }, + config.MethodNameGetIPNS: config.Method{ + RouterName: parallelRouterName, + }, + config.MethodNameProvide: config.Method{ + RouterName: parallelRouterName, + }, + config.MethodNamePutIPNS: config.Method{ + RouterName: parallelRouterName, + }, + }, }, } @@ -214,7 +248,19 @@ func GetNode(t *testing.T, reframeURLs ...string) *IpfsNode { D: syncds.MutexWrap(datastore.NewMapDatastore()), } - n, err := NewNode(context.Background(), &BuildCfg{Repo: r, Online: true, Routing: libp2p.NilRouterOption}) + n, err := NewNode(context.Background(), + &BuildCfg{ + Repo: r, + Online: true, + Routing: libp2p.ConstructDelegatedRouting( + cfg.Routing.Routers, + cfg.Routing.Methods, + cfg.Identity.PeerID, + cfg.Addresses.Swarm, + cfg.Identity.PrivKey, + ), + }, + ) require.NoError(t, err) return n @@ -240,6 +286,10 @@ func (drs *delegatedRoutingService) FindProviders(ctx context.Context, key cid.C return nil, errNotSupported } +func (drs *delegatedRoutingService) Provide(ctx context.Context, req *client.ProvideRequest) (<-chan client.ProvideAsyncResult, error) { + return nil, errNotSupported +} + func (drs *delegatedRoutingService) GetIPNS(ctx context.Context, id []byte) (<-chan client.GetIPNSAsyncResult, error) { ctx, cancel := context.WithCancel(ctx) ch := make(chan client.GetIPNSAsyncResult) diff --git a/core/coreapi/coreapi.go b/core/coreapi/coreapi.go index 515da6930..fb549171a 100644 --- a/core/coreapi/coreapi.go +++ b/core/coreapi/coreapi.go @@ -158,7 +158,7 @@ func (api *CoreAPI) WithOptions(opts ...options.ApiOption) (coreiface.CoreAPI, e n := api.nd - subApi := &CoreAPI{ + subAPI := &CoreAPI{ nctx: n.Context(), identity: n.Identity, @@ -190,14 +190,14 @@ func (api *CoreAPI) WithOptions(opts ...options.ApiOption) (coreiface.CoreAPI, e parentOpts: settings, } - subApi.checkOnline = func(allowOffline bool) error { + subAPI.checkOnline = func(allowOffline bool) error { if !n.IsOnline && !allowOffline { return coreiface.ErrOffline } return nil } - subApi.checkPublishAllowed = func() error { + subAPI.checkPublishAllowed = func() error { if n.Mounts.Ipns != nil && n.Mounts.Ipns.IsActive() { return errors.New("cannot manually publish while IPNS is mounted") } @@ -218,39 +218,39 @@ func (api *CoreAPI) WithOptions(opts ...options.ApiOption) (coreiface.CoreAPI, e return nil, fmt.Errorf("cannot specify negative resolve cache size") } - subApi.routing = offlineroute.NewOfflineRouter(subApi.repo.Datastore(), subApi.recordValidator) + subAPI.routing = offlineroute.NewOfflineRouter(subAPI.repo.Datastore(), subAPI.recordValidator) - subApi.namesys, err = namesys.NewNameSystem(subApi.routing, - namesys.WithDatastore(subApi.repo.Datastore()), - namesys.WithDNSResolver(subApi.dnsResolver), + subAPI.namesys, err = namesys.NewNameSystem(subAPI.routing, + namesys.WithDatastore(subAPI.repo.Datastore()), + namesys.WithDNSResolver(subAPI.dnsResolver), namesys.WithCache(cs)) if err != nil { return nil, fmt.Errorf("error constructing namesys: %w", err) } - subApi.provider = provider.NewOfflineProvider() + subAPI.provider = provider.NewOfflineProvider() - subApi.peerstore = nil - subApi.peerHost = nil - subApi.recordValidator = nil + subAPI.peerstore = nil + subAPI.peerHost = nil + subAPI.recordValidator = nil } if settings.Offline || !settings.FetchBlocks { - subApi.exchange = offlinexch.Exchange(subApi.blockstore) - subApi.blocks = bserv.New(subApi.blockstore, subApi.exchange) - subApi.dag = dag.NewDAGService(subApi.blocks) + subAPI.exchange = offlinexch.Exchange(subAPI.blockstore) + subAPI.blocks = bserv.New(subAPI.blockstore, subAPI.exchange) + subAPI.dag = dag.NewDAGService(subAPI.blocks) } - return subApi, nil + return subAPI, nil } // getSession returns new api backed by the same node with a read-only session DAG func (api *CoreAPI) getSession(ctx context.Context) *CoreAPI { - sesApi := *api + sesAPI := *api // TODO: We could also apply this to api.blocks, and compose into writable api, // but this requires some changes in blockservice/merkledag - sesApi.dag = dag.NewReadOnlyDagService(dag.NewSession(ctx, api.dag)) + sesAPI.dag = dag.NewReadOnlyDagService(dag.NewSession(ctx, api.dag)) - return &sesApi + return &sesAPI } diff --git a/core/coreapi/name.go b/core/coreapi/name.go index 3cd9850b4..69dc1137b 100644 --- a/core/coreapi/name.go +++ b/core/coreapi/name.go @@ -37,6 +37,8 @@ func (e *ipnsEntry) Value() path.Path { return e.value } +type requestContextKey string + // Publish announces new IPNS name and returns the new IPNS entry. func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.NamePublishOption) (coreiface.IpnsEntry, error) { ctx, span := tracing.Span(ctx, "CoreAPI.NameAPI", "Publish", trace.WithAttributes(attribute.String("path", p.String()))) @@ -76,7 +78,7 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam if options.TTL != nil { // nolint: staticcheck // non-backward compatible change - ctx = context.WithValue(ctx, "ipns-publish-ttl", *options.TTL) + ctx = context.WithValue(ctx, requestContextKey("ipns-publish-ttl"), *options.TTL) } eol := time.Now().Add(options.ValidTime) diff --git a/core/coreapi/pubsub.go b/core/coreapi/pubsub.go index a1c9a07f0..af29afecc 100644 --- a/core/coreapi/pubsub.go +++ b/core/coreapi/pubsub.go @@ -97,7 +97,7 @@ func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopt func (api *PubSubAPI) checkNode() (routing.Routing, error) { if api.pubSub == nil { - return nil, errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.") + return nil, errors.New("experimental pubsub feature not enabled, run daemon with --enable-pubsub-experiment to use") } err := api.checkOnline(false) diff --git a/core/coreapi/unixfs.go b/core/coreapi/unixfs.go index e0fe0eb13..d43bfe313 100644 --- a/core/coreapi/unixfs.go +++ b/core/coreapi/unixfs.go @@ -19,7 +19,6 @@ import ( bstore "github.com/ipfs/go-ipfs-blockstore" files "github.com/ipfs/go-ipfs-files" ipld "github.com/ipfs/go-ipld-format" - dag "github.com/ipfs/go-merkledag" merkledag "github.com/ipfs/go-merkledag" dagtest "github.com/ipfs/go-merkledag/test" mfs "github.com/ipfs/go-mfs" @@ -117,7 +116,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options } bserv := blockservice.New(addblockstore, exch) // hash security 001 - dserv := dag.NewDAGService(bserv) + dserv := merkledag.NewDAGService(bserv) // add a sync call to the DagService // this ensures that data written to the DagService is persisted to the underlying datastore diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go index d403919eb..0d0a234d9 100644 --- a/core/corehttp/gateway.go +++ b/core/corehttp/gateway.go @@ -77,7 +77,7 @@ func GatewayOption(writable bool, paths ...string) ServeOption { AddAccessControlHeaders(headers) - offlineApi, err := api.WithOptions(options.Api.Offline(true)) + offlineAPI, err := api.WithOptions(options.Api.Offline(true)) if err != nil { return nil, err } @@ -86,7 +86,7 @@ func GatewayOption(writable bool, paths ...string) ServeOption { Headers: headers, Writable: writable, FastDirIndexThreshold: int(cfg.Gateway.FastDirIndexThreshold.WithDefault(100)), - }, api, offlineApi) + }, api, offlineAPI) gateway = otelhttp.NewHandler(gateway, "Gateway.Request") @@ -146,7 +146,7 @@ func VersionOption() ServeOption { mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Commit: %s\n", version.CurrentCommit) fmt.Fprintf(w, "Client Version: %s\n", version.GetUserAgentVersion()) - fmt.Fprintf(w, "Protocol Version: %s\n", id.LibP2PVersion) + fmt.Fprintf(w, "Protocol Version: %s\n", id.DefaultProtocolVersion) }) return mux, nil } diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index ca3867001..a96799f58 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -13,7 +13,6 @@ import ( gopath "path" "regexp" "runtime/debug" - "strconv" "strings" "time" @@ -40,7 +39,7 @@ const ( ) var ( - onlyAscii = regexp.MustCompile("[[:^ascii:]]") + onlyASCII = regexp.MustCompile("[[:^ascii:]]") noModtime = time.Unix(0, 0) // disables Last-Modified header if passed as modtime ) @@ -69,7 +68,7 @@ type redirectTemplateData struct { type gatewayHandler struct { config GatewayConfig api NodeAPI - offlineApi NodeAPI + offlineAPI NodeAPI // generic metrics firstContentBlockGetMetric *prometheus.HistogramVec @@ -215,15 +214,15 @@ func newGatewayHistogramMetric(name string, help string) *prometheus.HistogramVe // NewGatewayHandler returns an http.Handler that can act as a gateway to IPFS content // offlineApi is a version of the API that should not make network requests for missing data -func NewGatewayHandler(c GatewayConfig, api NodeAPI, offlineApi NodeAPI) http.Handler { - return newGatewayHandler(c, api, offlineApi) +func NewGatewayHandler(c GatewayConfig, api NodeAPI, offlineAPI NodeAPI) http.Handler { + return newGatewayHandler(c, api, offlineAPI) } -func newGatewayHandler(c GatewayConfig, api NodeAPI, offlineApi NodeAPI) *gatewayHandler { +func newGatewayHandler(c GatewayConfig, api NodeAPI, offlineAPI NodeAPI) *gatewayHandler { i := &gatewayHandler{ config: c, api: api, - offlineApi: offlineApi, + offlineAPI: offlineAPI, // Improved Metrics // ---------------------------- // Time till the first content block (bar in /ipfs/cid/foo/bar) @@ -378,23 +377,6 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request return } - // Resolve path to the final DAG node for the ETag - resolvedPath, err := i.api.ResolvePath(r.Context(), contentPath) - switch err { - case nil: - case coreiface.ErrOffline: - webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusServiceUnavailable) - return - default: - // if Accept is text/html, see if ipfs-404.html is present - if i.servePretty404IfPresent(w, r, contentPath) { - logger.Debugw("serve pretty 404 if present") - return - } - webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusBadRequest) - return - } - // Detect when explicit Accept header or ?format parameter are present responseFormat, formatParams, err := customResponseFormat(r) if err != nil { @@ -402,6 +384,11 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request return } trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResponseFormat", responseFormat)) + + resolvedPath, contentPath, ok := i.handlePathResolution(w, r, responseFormat, contentPath, logger) + if !ok { + return + } trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResolvedPath", resolvedPath.String())) // Detect when If-None-Match HTTP header allows returning HTTP 304 Not Modified @@ -450,36 +437,6 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request } } -func (i *gatewayHandler) servePretty404IfPresent(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) bool { - resolved404Path, ctype, err := i.searchUpTreeFor404(r, contentPath) - if err != nil { - return false - } - - dr, err := i.api.Unixfs().Get(r.Context(), resolved404Path) - if err != nil { - return false - } - defer dr.Close() - - f, ok := dr.(files.File) - if !ok { - return false - } - - size, err := f.Size() - if err != nil { - return false - } - - log.Debugw("using pretty 404 file", "path", contentPath) - w.Header().Set("Content-Type", ctype) - w.Header().Set("Content-Length", strconv.FormatInt(size, 10)) - w.WriteHeader(http.StatusNotFound) - _, err = io.CopyN(w, f, size) - return err == nil -} - func (i *gatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) { p, err := i.api.Unixfs().Add(r.Context(), files.NewReaderFile(r.Body)) if err != nil { @@ -726,7 +683,7 @@ func addContentDispositionHeader(w http.ResponseWriter, r *http.Request, content // Set Content-Disposition to arbitrary filename and disposition func setContentDispositionHeader(w http.ResponseWriter, filename string, disposition string) { utf8Name := url.PathEscape(filename) - asciiName := url.PathEscape(onlyAscii.ReplaceAllLiteralString(filename, "_")) + asciiName := url.PathEscape(onlyASCII.ReplaceAllLiteralString(filename, "_")) w.Header().Set("Content-Disposition", fmt.Sprintf("%s; filename=\"%s\"; filename*=UTF-8''%s", disposition, asciiName, utf8Name)) } @@ -920,48 +877,6 @@ func customResponseFormat(r *http.Request) (mediaType string, params map[string] return "", nil, nil } -func (i *gatewayHandler) searchUpTreeFor404(r *http.Request, contentPath ipath.Path) (ipath.Resolved, string, error) { - filename404, ctype, err := preferred404Filename(r.Header.Values("Accept")) - if err != nil { - return nil, "", err - } - - pathComponents := strings.Split(contentPath.String(), "/") - - for idx := len(pathComponents); idx >= 3; idx-- { - pretty404 := gopath.Join(append(pathComponents[0:idx], filename404)...) - parsed404Path := ipath.New("/" + pretty404) - if parsed404Path.IsValid() != nil { - break - } - resolvedPath, err := i.api.ResolvePath(r.Context(), parsed404Path) - if err != nil { - continue - } - return resolvedPath, ctype, nil - } - - return nil, "", fmt.Errorf("no pretty 404 in any parent folder") -} - -func preferred404Filename(acceptHeaders []string) (string, string, error) { - // If we ever want to offer a 404 file for a different content type - // then this function will need to parse q weightings, but for now - // the presence of anything matching HTML is enough. - for _, acceptHeader := range acceptHeaders { - accepted := strings.Split(acceptHeader, ",") - for _, spec := range accepted { - contentType := strings.SplitN(spec, ";", 1)[0] - switch contentType { - case "*/*", "text/*", "text/html": - return "ipfs-404.html", "text/html", nil - } - } - } - - return "", "", fmt.Errorf("there is no 404 file for the requested content types") -} - // returns unquoted path with all special characters revealed as \u codes func debugStr(path string) string { q := fmt.Sprintf("%+q", path) @@ -971,11 +886,54 @@ func debugStr(path string) string { return q } +// Resolve the provided contentPath including any special handling related to +// the requested responseFormat. Returned ok flag indicates if gateway handler +// should continue processing the request. +func (i *gatewayHandler) handlePathResolution(w http.ResponseWriter, r *http.Request, responseFormat string, contentPath ipath.Path, logger *zap.SugaredLogger) (resolvedPath ipath.Resolved, newContentPath ipath.Path, ok bool) { + // Attempt to resolve the provided path. + resolvedPath, err := i.api.ResolvePath(r.Context(), contentPath) + + switch err { + case nil: + return resolvedPath, contentPath, true + case coreiface.ErrOffline: + webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusServiceUnavailable) + return nil, nil, false + default: + // The path can't be resolved. + if isUnixfsResponseFormat(responseFormat) { + // If we have origin isolation (subdomain gw, DNSLink website), + // and response type is UnixFS (default for website hosting) + // check for presence of _redirects file and apply rules defined there. + // See: https://github.com/ipfs/specs/pull/290 + if hasOriginIsolation(r) { + resolvedPath, newContentPath, ok, hadMatchingRule := i.serveRedirectsIfPresent(w, r, resolvedPath, contentPath, logger) + if hadMatchingRule { + logger.Debugw("applied a rule from _redirects file") + return resolvedPath, newContentPath, ok + } + } + + // if Accept is text/html, see if ipfs-404.html is present + // This logic isn't documented and will likely be removed at some point. + // Any 404 logic in _redirects above will have already run by this time, so it's really an extra fall back + if i.serveLegacy404IfPresent(w, r, contentPath) { + logger.Debugw("served legacy 404") + return nil, nil, false + } + } + + // Note: webError will replace http.StatusBadRequest with StatusNotFound if necessary + webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusBadRequest) + return nil, nil, false + } +} + // Detect 'Cache-Control: only-if-cached' in request and return data if it is already in the local datastore. // https://github.com/ipfs/specs/blob/main/http-gateways/PATH_GATEWAY.md#cache-control-request-header func (i *gatewayHandler) handleOnlyIfCached(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, logger *zap.SugaredLogger) (requestHandled bool) { if r.Header.Get("Cache-Control") == "only-if-cached" { - _, err := i.offlineApi.Block().Stat(r.Context(), contentPath) + _, err := i.offlineAPI.Block().Stat(r.Context(), contentPath) if err != nil { if r.Method == http.MethodHead { w.WriteHeader(http.StatusPreconditionFailed) diff --git a/core/corehttp/gateway_handler_unixfs__redirects.go b/core/corehttp/gateway_handler_unixfs__redirects.go new file mode 100644 index 000000000..81cf05731 --- /dev/null +++ b/core/corehttp/gateway_handler_unixfs__redirects.go @@ -0,0 +1,287 @@ +package corehttp + +import ( + "fmt" + "io" + "net/http" + gopath "path" + "strconv" + "strings" + + files "github.com/ipfs/go-ipfs-files" + redirects "github.com/ipfs/go-ipfs-redirects-file" + ipath "github.com/ipfs/interface-go-ipfs-core/path" + "go.uber.org/zap" +) + +// Resolving a UnixFS path involves determining if the provided `path.Path` exists and returning the `path.Resolved` +// corresponding to that path. For UnixFS, path resolution is more involved. +// +// When a path under requested CID does not exist, Gateway will check if a `_redirects` file exists +// underneath the root CID of the path, and apply rules defined there. +// See sepcification introduced in: https://github.com/ipfs/specs/pull/290 +// +// Scenario 1: +// If a path exists, we always return the `path.Resolved` corresponding to that path, regardless of the existence of a `_redirects` file. +// +// Scenario 2: +// If a path does not exist, usually we should return a `nil` resolution path and an error indicating that the path +// doesn't exist. However, a `_redirects` file may exist and contain a redirect rule that redirects that path to a different path. +// We need to evaluate the rule and perform the redirect if present. +// +// Scenario 3: +// Another possibility is that the path corresponds to a rewrite rule (i.e. a rule with a status of 200). +// In this case, we don't perform a redirect, but do need to return a `path.Resolved` and `path.Path` corresponding to +// the rewrite destination path. +// +// Note that for security reasons, redirect rules are only processed when the request has origin isolation. +// See https://github.com/ipfs/specs/pull/290 for more information. +func (i *gatewayHandler) serveRedirectsIfPresent(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, logger *zap.SugaredLogger) (newResolvedPath ipath.Resolved, newContentPath ipath.Path, continueProcessing bool, hadMatchingRule bool) { + redirectsFile := i.getRedirectsFile(r, contentPath, logger) + if redirectsFile != nil { + redirectRules, err := i.getRedirectRules(r, redirectsFile) + if err != nil { + internalWebError(w, err) + return nil, nil, false, true + } + + redirected, newPath, err := i.handleRedirectsFileRules(w, r, contentPath, redirectRules) + if err != nil { + err = fmt.Errorf("trouble processing _redirects file at %q: %w", redirectsFile.String(), err) + internalWebError(w, err) + return nil, nil, false, true + } + + if redirected { + return nil, nil, false, true + } + + // 200 is treated as a rewrite, so update the path and continue + if newPath != "" { + // Reassign contentPath and resolvedPath since the URL was rewritten + contentPath = ipath.New(newPath) + resolvedPath, err = i.api.ResolvePath(r.Context(), contentPath) + if err != nil { + internalWebError(w, err) + return nil, nil, false, true + } + + return resolvedPath, contentPath, true, true + } + } + // No matching rule, paths remain the same, continue regular processing + return resolvedPath, contentPath, true, false +} + +func (i *gatewayHandler) handleRedirectsFileRules(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, redirectRules []redirects.Rule) (redirected bool, newContentPath string, err error) { + // Attempt to match a rule to the URL path, and perform the corresponding redirect or rewrite + pathParts := strings.Split(contentPath.String(), "/") + if len(pathParts) > 3 { + // All paths should start with /ipfs/cid/, so get the path after that + urlPath := "/" + strings.Join(pathParts[3:], "/") + rootPath := strings.Join(pathParts[:3], "/") + // Trim off the trailing / + urlPath = strings.TrimSuffix(urlPath, "/") + + for _, rule := range redirectRules { + // Error right away if the rule is invalid + if !rule.MatchAndExpandPlaceholders(urlPath) { + continue + } + + // We have a match! + + // Rewrite + if rule.Status == 200 { + // Prepend the rootPath + toPath := rootPath + rule.To + return false, toPath, nil + } + + // Or 4xx + if rule.Status == 404 || rule.Status == 410 || rule.Status == 451 { + toPath := rootPath + rule.To + content4xxPath := ipath.New(toPath) + err := i.serve4xx(w, r, content4xxPath, rule.Status) + return true, toPath, err + } + + // Or redirect + if rule.Status >= 301 && rule.Status <= 308 { + http.Redirect(w, r, rule.To, rule.Status) + return true, "", nil + } + } + } + + // No redirects matched + return false, "", nil +} + +func (i *gatewayHandler) getRedirectRules(r *http.Request, redirectsFilePath ipath.Resolved) ([]redirects.Rule, error) { + // Convert the path into a file node + node, err := i.api.Unixfs().Get(r.Context(), redirectsFilePath) + if err != nil { + return nil, fmt.Errorf("could not get _redirects: %w", err) + } + defer node.Close() + + // Convert the node into a file + f, ok := node.(files.File) + if !ok { + return nil, fmt.Errorf("could not parse _redirects: %w", err) + } + + // Parse redirect rules from file + redirectRules, err := redirects.Parse(f) + if err != nil { + return nil, fmt.Errorf("could not parse _redirects: %w", err) + } + + return redirectRules, nil +} + +// Returns a resolved path to the _redirects file located in the root CID path of the requested path +func (i *gatewayHandler) getRedirectsFile(r *http.Request, contentPath ipath.Path, logger *zap.SugaredLogger) ipath.Resolved { + // contentPath is the full ipfs path to the requested resource, + // regardless of whether path or subdomain resolution is used. + rootPath := getRootPath(contentPath) + + // Check for _redirects file. + // Any path resolution failures are ignored and we just assume there's no _redirects file. + // Note that ignoring these errors also ensures that the use of the empty CID (bafkqaaa) in tests doesn't fail. + path := ipath.Join(rootPath, "_redirects") + resolvedPath, err := i.api.ResolvePath(r.Context(), path) + if err != nil { + return nil + } + return resolvedPath +} + +// Returns the root CID Path for the given path +func getRootPath(path ipath.Path) ipath.Path { + parts := strings.Split(path.String(), "/") + return ipath.New(gopath.Join("/", path.Namespace(), parts[2])) +} + +func (i *gatewayHandler) serve4xx(w http.ResponseWriter, r *http.Request, content4xxPath ipath.Path, status int) error { + resolved4xxPath, err := i.api.ResolvePath(r.Context(), content4xxPath) + if err != nil { + return err + } + + node, err := i.api.Unixfs().Get(r.Context(), resolved4xxPath) + if err != nil { + return err + } + defer node.Close() + + f, ok := node.(files.File) + if !ok { + return fmt.Errorf("could not convert node for %d page to file", status) + } + + size, err := f.Size() + if err != nil { + return fmt.Errorf("could not get size of %d page", status) + } + + log.Debugf("using _redirects: custom %d file at %q", status, content4xxPath) + w.Header().Set("Content-Type", "text/html") + w.Header().Set("Content-Length", strconv.FormatInt(size, 10)) + addCacheControlHeaders(w, r, content4xxPath, resolved4xxPath.Cid()) + w.WriteHeader(status) + _, err = io.CopyN(w, f, size) + return err +} + +func hasOriginIsolation(r *http.Request) bool { + _, gw := r.Context().Value(requestContextKey("gw-hostname")).(string) + _, dnslink := r.Context().Value("dnslink-hostname").(string) + + if gw || dnslink { + return true + } + + return false +} + +func isUnixfsResponseFormat(responseFormat string) bool { + // The implicit response format is UnixFS + return responseFormat == "" +} + +// Deprecated: legacy ipfs-404.html files are superseded by _redirects file +// This is provided only for backward-compatibility, until websites migrate +// to 404s managed via _redirects file (https://github.com/ipfs/specs/pull/290) +func (i *gatewayHandler) serveLegacy404IfPresent(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) bool { + resolved404Path, ctype, err := i.searchUpTreeFor404(r, contentPath) + if err != nil { + return false + } + + dr, err := i.api.Unixfs().Get(r.Context(), resolved404Path) + if err != nil { + return false + } + defer dr.Close() + + f, ok := dr.(files.File) + if !ok { + return false + } + + size, err := f.Size() + if err != nil { + return false + } + + log.Debugw("using pretty 404 file", "path", contentPath) + w.Header().Set("Content-Type", ctype) + w.Header().Set("Content-Length", strconv.FormatInt(size, 10)) + w.WriteHeader(http.StatusNotFound) + _, err = io.CopyN(w, f, size) + return err == nil +} + +func (i *gatewayHandler) searchUpTreeFor404(r *http.Request, contentPath ipath.Path) (ipath.Resolved, string, error) { + filename404, ctype, err := preferred404Filename(r.Header.Values("Accept")) + if err != nil { + return nil, "", err + } + + pathComponents := strings.Split(contentPath.String(), "/") + + for idx := len(pathComponents); idx >= 3; idx-- { + pretty404 := gopath.Join(append(pathComponents[0:idx], filename404)...) + parsed404Path := ipath.New("/" + pretty404) + if parsed404Path.IsValid() != nil { + break + } + resolvedPath, err := i.api.ResolvePath(r.Context(), parsed404Path) + if err != nil { + continue + } + return resolvedPath, ctype, nil + } + + return nil, "", fmt.Errorf("no pretty 404 in any parent folder") +} + +func preferred404Filename(acceptHeaders []string) (string, string, error) { + // If we ever want to offer a 404 file for a different content type + // then this function will need to parse q weightings, but for now + // the presence of anything matching HTML is enough. + for _, acceptHeader := range acceptHeaders { + accepted := strings.Split(acceptHeader, ",") + for _, spec := range accepted { + contentType := strings.SplitN(spec, ";", 1)[0] + switch contentType { + case "*/*", "text/*", "text/html": + return "ipfs-404.html", "text/html", nil + } + } + } + + return "", "", fmt.Errorf("there is no 404 file for the requested content types") +} diff --git a/core/corehttp/gateway_handler_unixfs_dir.go b/core/corehttp/gateway_handler_unixfs_dir.go index a6ab7cb55..1c803b13b 100644 --- a/core/corehttp/gateway_handler_unixfs_dir.go +++ b/core/corehttp/gateway_handler_unixfs_dir.go @@ -39,10 +39,10 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit webError(w, "failed to parse request path", err, http.StatusInternalServerError) return } - originalUrlPath := requestURI.Path + originalURLPath := requestURI.Path // Ensure directory paths end with '/' - if originalUrlPath[len(originalUrlPath)-1] != '/' { + if originalURLPath[len(originalURLPath)-1] != '/' { // don't redirect to trailing slash if it's go get // https://github.com/ipfs/kubo/pull/3963 goget := r.URL.Query().Get("go-get") == "1" @@ -53,7 +53,7 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit suffix = suffix + "?" + r.URL.RawQuery } // /ipfs/cid/foo?bar must be redirected to /ipfs/cid/foo/?bar - redirectURL := originalUrlPath + suffix + redirectURL := originalURLPath + suffix logger.Debugw("directory location moved permanently", "status", http.StatusMovedPermanently) http.Redirect(w, r, redirectURL, http.StatusMovedPermanently) return @@ -125,7 +125,7 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit di := directoryItem{ Size: "", // no size because we did not fetch child nodes Name: link.Name, - Path: gopath.Join(originalUrlPath, link.Name), + Path: gopath.Join(originalURLPath, link.Name), Hash: hash, ShortHash: shortHash(hash), } @@ -149,7 +149,7 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit // construct the correct back link // https://github.com/ipfs/kubo/issues/1365 - var backLink string = originalUrlPath + backLink := originalURLPath // don't go further up than /ipfs/$hash/ pathSplit := path.SplitList(contentPath.String()) @@ -185,7 +185,7 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit var gwURL string // Get gateway hostname and build gateway URL. - if h, ok := r.Context().Value("gw-hostname").(string); ok { + if h, ok := r.Context().Value(requestContextKey("gw-hostname")).(string); ok { gwURL = "//" + h } else { gwURL = "" diff --git a/core/corehttp/gateway_indexPage.go b/core/corehttp/gateway_indexPage.go index 1168d6556..19e444da3 100644 --- a/core/corehttp/gateway_indexPage.go +++ b/core/corehttp/gateway_indexPage.go @@ -117,8 +117,8 @@ func init() { // custom template-escaping function to escape a full path, including '#' and '?' urlEscape := func(rawUrl string) string { - pathUrl := url.URL{Path: rawUrl} - return pathUrl.String() + pathURL := url.URL{Path: rawUrl} + return pathURL.String() } // Directory listing template diff --git a/core/corehttp/gateway_test.go b/core/corehttp/gateway_test.go index 380a3ae0c..f4dda631e 100644 --- a/core/corehttp/gateway_test.go +++ b/core/corehttp/gateway_test.go @@ -652,7 +652,7 @@ func TestVersion(t *testing.T) { t.Fatalf("response doesn't contain client version:\n%s", s) } - if !strings.Contains(s, "Protocol Version: "+id.LibP2PVersion) { + if !strings.Contains(s, "Protocol Version: "+id.DefaultProtocolVersion) { t.Fatalf("response doesn't contain protocol version:\n%s", s) } } diff --git a/core/corehttp/hostname.go b/core/corehttp/hostname.go index 3d022fc5a..39e857aad 100644 --- a/core/corehttp/hostname.go +++ b/core/corehttp/hostname.go @@ -84,7 +84,8 @@ func HostnameOption() ServeOption { if gw.UseSubdomains { // Yes, redirect if applicable // Example: dweb.link/ipfs/{cid} → {cid}.ipfs.dweb.link - newURL, err := toSubdomainURL(host, r.URL.Path, r, coreAPI) + useInlinedDNSLink := gw.InlineDNSLink.WithDefault(config.DefaultInlineDNSLink) + newURL, err := toSubdomainURL(host, r.URL.Path, r, useInlinedDNSLink, coreAPI) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return @@ -132,6 +133,9 @@ func HostnameOption() ServeOption { // Assemble original path prefix. pathPrefix := "/" + ns + "/" + rootID + // Retrieve whether or not we should inline DNSLink. + useInlinedDNSLink := gw.InlineDNSLink.WithDefault(config.DefaultInlineDNSLink) + // Does this gateway _handle_ subdomains AND this path? if !(gw.UseSubdomains && hasPrefix(pathPrefix, gw.Paths...)) { // If not, resource does not exist, return 404 @@ -149,7 +153,7 @@ func HostnameOption() ServeOption { } if !strings.HasPrefix(r.Host, dnsCID) { dnsPrefix := "/" + ns + "/" + dnsCID - newURL, err := toSubdomainURL(gwHostname, dnsPrefix+r.URL.Path, r, coreAPI) + newURL, err := toSubdomainURL(gwHostname, dnsPrefix+r.URL.Path, r, useInlinedDNSLink, coreAPI) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return @@ -165,7 +169,7 @@ func HostnameOption() ServeOption { // Do we need to fix multicodec in PeerID represented as CIDv1? if isPeerIDNamespace(ns) { if rootCID.Type() != cid.Libp2pKey { - newURL, err := toSubdomainURL(gwHostname, pathPrefix+r.URL.Path, r, coreAPI) + newURL, err := toSubdomainURL(gwHostname, pathPrefix+r.URL.Path, r, useInlinedDNSLink, coreAPI) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return @@ -221,7 +225,8 @@ func HostnameOption() ServeOption { if !cfg.Gateway.NoDNSLink && isDNSLinkName(r.Context(), coreAPI, host) { // rewrite path and handle as DNSLink r.URL.Path = "/ipns/" + stripPort(host) + r.URL.Path - childMux.ServeHTTP(w, withHostnameContext(r, host)) + ctx := context.WithValue(r.Context(), requestContextKey("dnslink-hostname"), host) + childMux.ServeHTTP(w, withHostnameContext(r.WithContext(ctx), host)) return } @@ -242,6 +247,8 @@ type wildcardHost struct { spec *config.GatewaySpec } +type requestContextKey string + // Extends request context to include hostname of a canonical gateway root // (subdomain root or dnslink fqdn) func withHostnameContext(r *http.Request, hostname string) *http.Request { @@ -250,7 +257,7 @@ func withHostnameContext(r *http.Request, hostname string) *http.Request { // Host header, subdomain gateways have more comples rules (knownSubdomainDetails) // More: https://github.com/ipfs/dir-index-html/issues/42 // nolint: staticcheck // non-backward compatible change - ctx := context.WithValue(r.Context(), "gw-hostname", hostname) + ctx := context.WithValue(r.Context(), requestContextKey("gw-hostname"), hostname) return r.WithContext(ctx) } @@ -448,7 +455,7 @@ func toDNSLinkFQDN(dnsLabel string) (fqdn string) { } // Converts a hostname/path to a subdomain-based URL, if applicable. -func toSubdomainURL(hostname, path string, r *http.Request, ipfs iface.CoreAPI) (redirURL string, err error) { +func toSubdomainURL(hostname, path string, r *http.Request, inlineDNSLink bool, ipfs iface.CoreAPI) (redirURL string, err error) { var scheme, ns, rootID, rest string query := r.URL.RawQuery @@ -551,7 +558,7 @@ func toSubdomainURL(hostname, path string, r *http.Request, ipfs iface.CoreAPI) // can be loaded from a subdomain gateway with a wildcard TLS cert if // represented as a single DNS label: // https://my-v--long-example-com.ipns.dweb.link - if isHTTPS && ns == "ipns" && strings.Contains(rootID, ".") { + if (inlineDNSLink || isHTTPS) && ns == "ipns" && strings.Contains(rootID, ".") { if isDNSLinkName(r.Context(), ipfs, rootID) { // my.v-long.example.com → my-v--long-example-com dnsLabel, err := toDNSLinkDNSLabel(rootID) diff --git a/core/corehttp/hostname_test.go b/core/corehttp/hostname_test.go index 60b537239..6f0713528 100644 --- a/core/corehttp/hostname_test.go +++ b/core/corehttp/hostname_test.go @@ -36,35 +36,39 @@ func TestToSubdomainURL(t *testing.T) { for _, test := range []struct { // in: - request *http.Request - gwHostname string - path string + request *http.Request + gwHostname string + inlineDNSLink bool + path string // out: url string err error }{ // DNSLink - {httpRequest, "localhost", "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost/", nil}, + {httpRequest, "localhost", false, "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost/", nil}, // Hostname with port - {httpRequest, "localhost:8080", "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost:8080/", nil}, + {httpRequest, "localhost:8080", false, "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost:8080/", nil}, // CIDv0 → CIDv1base32 - {httpRequest, "localhost", "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.localhost/", nil}, + {httpRequest, "localhost", false, "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.localhost/", nil}, // CIDv1 with long sha512 - {httpRequest, "localhost", "/ipfs/bafkrgqe3ohjcjplc6n4f3fwunlj6upltggn7xqujbsvnvyw764srszz4u4rshq6ztos4chl4plgg4ffyyxnayrtdi5oc4xb2332g645433aeg", "", errors.New("CID incompatible with DNS label length limit of 63: kf1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5oj")}, + {httpRequest, "localhost", false, "/ipfs/bafkrgqe3ohjcjplc6n4f3fwunlj6upltggn7xqujbsvnvyw764srszz4u4rshq6ztos4chl4plgg4ffyyxnayrtdi5oc4xb2332g645433aeg", "", errors.New("CID incompatible with DNS label length limit of 63: kf1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5oj")}, // PeerID as CIDv1 needs to have libp2p-key multicodec - {httpRequest, "localhost", "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", "http://k2k4r8n0flx3ra0y5dr8fmyvwbzy3eiztmtq6th694k5a3rznayp3e4o.ipns.localhost/", nil}, - {httpRequest, "localhost", "/ipns/bafybeickencdqw37dpz3ha36ewrh4undfjt2do52chtcky4rxkj447qhdm", "http://k2k4r8l9ja7hkzynavdqup76ou46tnvuaqegbd04a4o1mpbsey0meucb.ipns.localhost/", nil}, + {httpRequest, "localhost", false, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", "http://k2k4r8n0flx3ra0y5dr8fmyvwbzy3eiztmtq6th694k5a3rznayp3e4o.ipns.localhost/", nil}, + {httpRequest, "localhost", false, "/ipns/bafybeickencdqw37dpz3ha36ewrh4undfjt2do52chtcky4rxkj447qhdm", "http://k2k4r8l9ja7hkzynavdqup76ou46tnvuaqegbd04a4o1mpbsey0meucb.ipns.localhost/", nil}, // PeerID: ed25519+identity multihash → CIDv1Base36 - {httpRequest, "localhost", "/ipns/12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5", "http://k51qzi5uqu5di608geewp3nqkg0bpujoasmka7ftkyxgcm3fh1aroup0gsdrna.ipns.localhost/", nil}, - {httpRequest, "sub.localhost", "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.sub.localhost/", nil}, + {httpRequest, "localhost", false, "/ipns/12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5", "http://k51qzi5uqu5di608geewp3nqkg0bpujoasmka7ftkyxgcm3fh1aroup0gsdrna.ipns.localhost/", nil}, + {httpRequest, "sub.localhost", false, "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.sub.localhost/", nil}, // HTTPS requires DNSLink name to fit in a single DNS label – see "Option C" from https://github.com/ipfs/in-web-browsers/issues/169 - {httpRequest, "dweb.link", "/ipns/dnslink.long-name.example.com", "http://dnslink.long-name.example.com.ipns.dweb.link/", nil}, - {httpsRequest, "dweb.link", "/ipns/dnslink.long-name.example.com", "https://dnslink-long--name-example-com.ipns.dweb.link/", nil}, - {httpsProxiedRequest, "dweb.link", "/ipns/dnslink.long-name.example.com", "https://dnslink-long--name-example-com.ipns.dweb.link/", nil}, + {httpRequest, "dweb.link", false, "/ipns/dnslink.long-name.example.com", "http://dnslink.long-name.example.com.ipns.dweb.link/", nil}, + {httpsRequest, "dweb.link", false, "/ipns/dnslink.long-name.example.com", "https://dnslink-long--name-example-com.ipns.dweb.link/", nil}, + {httpsProxiedRequest, "dweb.link", false, "/ipns/dnslink.long-name.example.com", "https://dnslink-long--name-example-com.ipns.dweb.link/", nil}, + // HTTP requests can also be converted to fit into a single DNS label - https://github.com/ipfs/kubo/issues/9243 + {httpRequest, "localhost", true, "/ipns/dnslink.long-name.example.com", "http://dnslink-long--name-example-com.ipns.localhost/", nil}, + {httpRequest, "dweb.link", true, "/ipns/dnslink.long-name.example.com", "http://dnslink-long--name-example-com.ipns.dweb.link/", nil}, } { - url, err := toSubdomainURL(test.gwHostname, test.path, test.request, coreAPI) + url, err := toSubdomainURL(test.gwHostname, test.path, test.request, test.inlineDNSLink, coreAPI) if url != test.url || !equalError(err, test.err) { - t.Errorf("(%s, %s) returned (%s, %v), expected (%s, %v)", test.gwHostname, test.path, url, err, test.url, test.err) + t.Errorf("(%s, %v, %s) returned (%s, %v), expected (%s, %v)", test.gwHostname, test.inlineDNSLink, test.path, url, err, test.url, test.err) } } } diff --git a/core/corehttp/lazyseek_test.go b/core/corehttp/lazyseek_test.go index 2733acafb..49aca0a0e 100644 --- a/core/corehttp/lazyseek_test.go +++ b/core/corehttp/lazyseek_test.go @@ -11,14 +11,14 @@ type badSeeker struct { io.ReadSeeker } -var badSeekErr = fmt.Errorf("I'm a bad seeker") +var errBadSeek = fmt.Errorf("bad seeker") func (bs badSeeker) Seek(offset int64, whence int) (int64, error) { off, err := bs.ReadSeeker.Seek(0, io.SeekCurrent) if err != nil { panic(err) } - return off, badSeekErr + return off, errBadSeek } func TestLazySeekerError(t *testing.T) { @@ -73,7 +73,7 @@ func TestLazySeekerError(t *testing.T) { if err == nil { t.Fatalf("expected an error, got output %s", string(b)) } - if err != badSeekErr { + if err != errBadSeek { t.Fatalf("expected a bad seek error, got %s", err) } if len(b) != 0 { diff --git a/core/corehttp/metrics.go b/core/corehttp/metrics.go index da2d576a2..e26be1ca9 100644 --- a/core/corehttp/metrics.go +++ b/core/corehttp/metrics.go @@ -164,7 +164,7 @@ type IpfsNodeCollector struct { Node *core.IpfsNode } -func (_ IpfsNodeCollector) Describe(ch chan<- *prometheus.Desc) { +func (IpfsNodeCollector) Describe(ch chan<- *prometheus.Desc) { ch <- peersTotalMetric } diff --git a/core/corehttp/p2p_proxy.go b/core/corehttp/p2p_proxy.go index 44c20c2ad..e239f47cd 100644 --- a/core/corehttp/p2p_proxy.go +++ b/core/corehttp/p2p_proxy.go @@ -58,11 +58,11 @@ func parseRequest(request *http.Request) (*proxyRequest, error) { split := strings.SplitN(path, "/", 5) if len(split) < 5 { - return nil, fmt.Errorf("Invalid request path '%s'", path) + return nil, fmt.Errorf("invalid request path '%s'", path) } if _, err := peer.Decode(split[2]); err != nil { - return nil, fmt.Errorf("Invalid request path '%s'", path) + return nil, fmt.Errorf("invalid request path '%s'", path) } if split[3] == "http" { @@ -71,7 +71,7 @@ func parseRequest(request *http.Request) (*proxyRequest, error) { split = strings.SplitN(path, "/", 7) if len(split) < 7 || split[3] != "x" || split[5] != "http" { - return nil, fmt.Errorf("Invalid request path '%s'", path) + return nil, fmt.Errorf("invalid request path '%s'", path) } return &proxyRequest{split[2], protocol.ID("/x/" + split[4] + "/http"), split[6]}, nil diff --git a/core/corehttp/redirect.go b/core/corehttp/redirect.go index 5af596bd6..bcd536d23 100644 --- a/core/corehttp/redirect.go +++ b/core/corehttp/redirect.go @@ -24,5 +24,5 @@ type redirectHandler struct { } func (i *redirectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, i.path, 302) + http.Redirect(w, r, i.path, http.StatusFound) } diff --git a/core/corehttp/webui.go b/core/corehttp/webui.go index 4952dc16f..98e69cd5c 100644 --- a/core/corehttp/webui.go +++ b/core/corehttp/webui.go @@ -3,7 +3,7 @@ package corehttp // TODO: move to IPNS const WebUIPath = "/ipfs/bafybeiageaoxg6d7npaof6eyzqbwvbubyler7bq44hayik2hvqcggg7d2y" // v2.18.1 -// this is a list of all past webUI paths. +// WebUIPaths is a list of all past webUI paths. var WebUIPaths = []string{ WebUIPath, "/ipfs/bafybeidb5eryh72zajiokdggzo7yct2d6hhcflncji5im2y5w26uuygdsm", diff --git a/core/node/bitswap.go b/core/node/bitswap.go index 432866395..2b9cf641a 100644 --- a/core/node/bitswap.go +++ b/core/node/bitswap.go @@ -7,7 +7,7 @@ import ( "github.com/ipfs/go-bitswap/network" blockstore "github.com/ipfs/go-ipfs-blockstore" exchange "github.com/ipfs/go-ipfs-exchange-interface" - config "github.com/ipfs/kubo/config" + "github.com/ipfs/kubo/config" irouting "github.com/ipfs/kubo/routing" "github.com/libp2p/go-libp2p/core/host" "go.uber.org/fx" @@ -15,19 +15,24 @@ import ( "github.com/ipfs/kubo/core/node/helpers" ) +// Docs: https://github.com/ipfs/kubo/blob/master/docs/config.md#internalbitswap const ( - // Docs: https://github.com/ipfs/kubo/blob/master/docs/config.md#internalbitswap DefaultEngineBlockstoreWorkerCount = 128 DefaultTaskWorkerCount = 8 DefaultEngineTaskWorkerCount = 8 DefaultMaxOutstandingBytesPerPeer = 1 << 20 ) -// OnlineExchange creates new LibP2P backed block exchange (BitSwap) -func OnlineExchange(cfg *config.Config, provide bool) interface{} { - return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, rt irouting.TieredRouter, bs blockstore.GCBlockstore) exchange.Interface { - bitswapNetwork := network.NewFromIpfsHost(host, rt) +type bitswapOptionsOut struct { + fx.Out + BitswapOpts []bitswap.Option `group:"bitswap-options,flatten"` +} + +// BitswapOptions creates configuration options for Bitswap from the config file +// and whether to provide data. +func BitswapOptions(cfg *config.Config, provide bool) interface{} { + return func() bitswapOptionsOut { var internalBsCfg config.InternalBitswap if cfg.Internal.Bitswap != nil { internalBsCfg = *cfg.Internal.Bitswap @@ -40,13 +45,34 @@ func OnlineExchange(cfg *config.Config, provide bool) interface{} { bitswap.EngineTaskWorkerCount(int(internalBsCfg.EngineTaskWorkerCount.WithDefault(DefaultEngineTaskWorkerCount))), bitswap.MaxOutstandingBytesPerPeer(int(internalBsCfg.MaxOutstandingBytesPerPeer.WithDefault(DefaultMaxOutstandingBytesPerPeer))), } - exch := bitswap.New(helpers.LifecycleCtx(mctx, lc), bitswapNetwork, bs, opts...) + + return bitswapOptionsOut{BitswapOpts: opts} + } +} + +type onlineExchangeIn struct { + fx.In + + Mctx helpers.MetricsCtx + Host host.Host + Rt irouting.ProvideManyRouter + Bs blockstore.GCBlockstore + BitswapOpts []bitswap.Option `group:"bitswap-options"` +} + +// OnlineExchange creates new LibP2P backed block exchange (BitSwap). +// Additional options to bitswap.New can be provided via the "bitswap-options" +// group. +func OnlineExchange() interface{} { + return func(in onlineExchangeIn, lc fx.Lifecycle) exchange.Interface { + bitswapNetwork := network.NewFromIpfsHost(in.Host, in.Rt) + + exch := bitswap.New(helpers.LifecycleCtx(in.Mctx, lc), bitswapNetwork, in.Bs, in.BitswapOpts...) lc.Append(fx.Hook{ OnStop: func(ctx context.Context) error { return exch.Close() }, }) return exch - } } diff --git a/core/node/groups.go b/core/node/groups.go index b17980789..fca984650 100644 --- a/core/node/groups.go +++ b/core/node/groups.go @@ -165,7 +165,6 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option { fx.Provide(libp2p.ContentRouting), fx.Provide(libp2p.BaseRouting(cfg.Experimental.AcceleratedDHTClient)), - fx.Provide(libp2p.DelegatedRouting(cfg.Routing.Routers)), maybeProvide(libp2p.PubsubRouter, bcfg.getOpt("ipnsps")), maybeProvide(libp2p.BandwidthCounter, !cfg.Swarm.DisableBandwidthMetrics), @@ -289,7 +288,8 @@ func Online(bcfg *BuildCfg, cfg *config.Config) fx.Option { shouldBitswapProvide := !cfg.Experimental.StrategicProviding return fx.Options( - fx.Provide(OnlineExchange(cfg, shouldBitswapProvide)), + fx.Provide(BitswapOptions(cfg, shouldBitswapProvide)), + fx.Provide(OnlineExchange()), maybeProvide(Graphsync, cfg.Experimental.GraphsyncEnabled), fx.Provide(DNSResolver), fx.Provide(Namesys(ipnsCacheSize)), diff --git a/core/node/ipns.go b/core/node/ipns.go index 36f330b9b..0500c7be4 100644 --- a/core/node/ipns.go +++ b/core/node/ipns.go @@ -11,11 +11,10 @@ import ( "github.com/libp2p/go-libp2p/core/peerstore" madns "github.com/multiformats/go-multiaddr-dns" - irouting "github.com/ipfs/kubo/routing" - "github.com/ipfs/go-namesys" "github.com/ipfs/go-namesys/republisher" "github.com/ipfs/kubo/repo" + irouting "github.com/ipfs/kubo/routing" ) const DefaultIpnsCacheSize = 128 @@ -29,8 +28,8 @@ func RecordValidator(ps peerstore.Peerstore) record.Validator { } // Namesys creates new name system -func Namesys(cacheSize int) func(rt irouting.TieredRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) { - return func(rt irouting.TieredRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) { +func Namesys(cacheSize int) func(rt irouting.ProvideManyRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) { + return func(rt irouting.ProvideManyRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) { opts := []namesys.Option{ namesys.WithDatastore(repo.Datastore()), namesys.WithDNSResolver(rslv), diff --git a/core/node/libp2p/libp2p.go b/core/node/libp2p/libp2p.go index c041139d1..b36197152 100644 --- a/core/node/libp2p/libp2p.go +++ b/core/node/libp2p/libp2p.go @@ -25,7 +25,6 @@ type Libp2pOpts struct { Opts []libp2p.Option `group:"libp2p"` } -// Misc options var UserAgent = simpleOpt(libp2p.UserAgent(version.GetUserAgentVersion())) func ConnectionManager(low, high int, grace time.Duration) func() (opts Libp2pOpts, err error) { diff --git a/core/node/libp2p/rcmgr.go b/core/node/libp2p/rcmgr.go index 2764f67af..c24d03108 100644 --- a/core/node/libp2p/rcmgr.go +++ b/core/node/libp2p/rcmgr.go @@ -28,7 +28,7 @@ import ( const NetLimitDefaultFilename = "limit.json" const NetLimitTraceFilename = "rcmgr.json.gz" -var NoResourceMgrError = fmt.Errorf("missing ResourceMgr: make sure the daemon is running with Swarm.ResourceMgr.Enabled") +var ErrNoResourceMgr = fmt.Errorf("missing ResourceMgr: make sure the daemon is running with Swarm.ResourceMgr.Enabled") func ResourceManager(cfg config.SwarmConfig) interface{} { return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, repo repo.Repo) (network.ResourceManager, Libp2pOpts, error) { @@ -136,7 +136,7 @@ func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) { case scope == "all": rapi, ok := mgr.(rcmgr.ResourceManagerState) if !ok { // NullResourceManager - return result, NoResourceMgrError + return result, ErrNoResourceMgr } stat := rapi.Stat() @@ -223,7 +223,7 @@ func NetLimit(mgr network.ResourceManager, scope string) (rcmgr.BaseLimit, error getLimit := func(s network.ResourceScope) error { limiter, ok := s.(rcmgr.ResourceScopeLimiter) if !ok { // NullResourceManager - return NoResourceMgrError + return ErrNoResourceMgr } limit := limiter.Limit() switch l := limit.(type) { @@ -271,7 +271,7 @@ func NetSetLimit(mgr network.ResourceManager, repo repo.Repo, scope string, limi setLimit := func(s network.ResourceScope) error { limiter, ok := s.(rcmgr.ResourceScopeLimiter) if !ok { // NullResourceManager - return NoResourceMgrError + return ErrNoResourceMgr } limiter.SetLimit(&limit) diff --git a/core/node/libp2p/rcmgr_defaults.go b/core/node/libp2p/rcmgr_defaults.go index 09154f782..e09a59845 100644 --- a/core/node/libp2p/rcmgr_defaults.go +++ b/core/node/libp2p/rcmgr_defaults.go @@ -155,7 +155,7 @@ func checkImplicitDefaults() { } if !ok { - log.Errorf("===> OOF! go-libp2p reduced DefaultServiceLimits\n" + + log.Errorf("===> OOF! go-libp2p changed DefaultServiceLimits\n" + "=> See the aboce reduced values for info.\n" + "=> go-libp2p SetDefaultServiceLimits update needs a review:\n" + "Please inspect if changes impact go-ipfs users, and update expectedDefaultServiceLimits in rcmgr_defaults.go to remove this message", @@ -376,7 +376,7 @@ const expectedDefaultLimits = `{ "ConnsInbound": 1, "ConnsOutbound": 1, "FD": 1, - "Memory": 1048576 + "Memory": 33554432 }, "ConnLimitIncrease": { "Streams": 0, diff --git a/core/node/libp2p/rcmgr_logging.go b/core/node/libp2p/rcmgr_logging.go index 21b7fe65e..4b50cdc2e 100644 --- a/core/node/libp2p/rcmgr_logging.go +++ b/core/node/libp2p/rcmgr_logging.go @@ -32,6 +32,7 @@ type loggingScope struct { } var _ network.ResourceManager = (*loggingResourceManager)(nil) +var _ rcmgr.ResourceManagerState = (*loggingResourceManager)(nil) func (n *loggingResourceManager) start(ctx context.Context) { logInterval := n.logInterval @@ -103,6 +104,40 @@ func (n *loggingResourceManager) Close() error { return n.delegate.Close() } +func (n *loggingResourceManager) ListServices() []string { + rapi, ok := n.delegate.(rcmgr.ResourceManagerState) + if !ok { + return nil + } + + return rapi.ListServices() +} +func (n *loggingResourceManager) ListProtocols() []protocol.ID { + rapi, ok := n.delegate.(rcmgr.ResourceManagerState) + if !ok { + return nil + } + + return rapi.ListProtocols() +} +func (n *loggingResourceManager) ListPeers() []peer.ID { + rapi, ok := n.delegate.(rcmgr.ResourceManagerState) + if !ok { + return nil + } + + return rapi.ListPeers() +} + +func (n *loggingResourceManager) Stat() rcmgr.ResourceManagerStat { + rapi, ok := n.delegate.(rcmgr.ResourceManagerState) + if !ok { + return rcmgr.ResourceManagerStat{} + } + + return rapi.Stat() +} + func (s *loggingScope) ReserveMemory(size int, prio uint8) error { err := s.delegate.ReserveMemory(size, prio) s.countErrs(err) diff --git a/core/node/libp2p/relay.go b/core/node/libp2p/relay.go index 16632a7ae..c39b2fae8 100644 --- a/core/node/libp2p/relay.go +++ b/core/node/libp2p/relay.go @@ -1,6 +1,8 @@ package libp2p import ( + "context" + "github.com/ipfs/kubo/config" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/peer" @@ -74,17 +76,25 @@ func MaybeAutoRelay(staticRelays []string, cfgPeering config.Peering, enabled bo return fx.Options( // Provide AutoRelay option fx.Provide(func() (opts Libp2pOpts, err error) { - opts.Opts = append(opts.Opts, libp2p.EnableAutoRelay(autorelay.WithPeerSource(func(numPeers int) <-chan peer.AddrInfo { + opts.Opts = append(opts.Opts, libp2p.EnableAutoRelay(autorelay.WithPeerSource(func(ctx context.Context, numPeers int) <-chan peer.AddrInfo { // TODO(9257): make this code smarter (have a state and actually try to grow the search outward) instead of a long running task just polling our K cluster. - r := make(chan peer.AddrInfo, numPeers) + r := make(chan peer.AddrInfo) go func() { defer close(r) for ; numPeers != 0; numPeers-- { - v, ok := <-peerChan - if !ok { + select { + case v, ok := <-peerChan: + if !ok { + return + } + select { + case r <- v: + case <-ctx.Done(): + return + } + case <-ctx.Done(): return } - r <- v } }() return r diff --git a/core/node/libp2p/routing.go b/core/node/libp2p/routing.go index 4825bbc12..21afe292d 100644 --- a/core/node/libp2p/routing.go +++ b/core/node/libp2p/routing.go @@ -129,39 +129,6 @@ func BaseRouting(experimentalDHTClient bool) interface{} { } } -type delegatedRouterOut struct { - fx.Out - - Routers []Router `group:"routers,flatten"` - ContentRouter []routing.ContentRouting `group:"content-routers,flatten"` -} - -func DelegatedRouting(routers map[string]config.Router) interface{} { - return func() (delegatedRouterOut, error) { - out := delegatedRouterOut{} - - for _, v := range routers { - if !v.Enabled.WithDefault(true) { - continue - } - - r, err := irouting.RoutingFromConfig(v) - if err != nil { - return out, err - } - - out.Routers = append(out.Routers, Router{ - Routing: r, - Priority: irouting.GetPriority(v.Parameters), - }) - - out.ContentRouter = append(out.ContentRouter, r) - } - - return out, nil - } -} - type p2pOnlineContentRoutingIn struct { fx.In @@ -195,24 +162,23 @@ type p2pOnlineRoutingIn struct { // Routing will get all routers obtained from different methods // (delegated routers, pub-sub, and so on) and add them all together // using a TieredRouter. -func Routing(in p2pOnlineRoutingIn) irouting.TieredRouter { +func Routing(in p2pOnlineRoutingIn) irouting.ProvideManyRouter { routers := in.Routers sort.SliceStable(routers, func(i, j int) bool { return routers[i].Priority < routers[j].Priority }) - irouters := make([]routing.Routing, len(routers)) - for i, v := range routers { - irouters[i] = v.Routing + var cRouters []*routinghelpers.ParallelRouter + for _, v := range routers { + cRouters = append(cRouters, &routinghelpers.ParallelRouter{ + Timeout: 5 * time.Minute, + IgnoreError: true, + Router: v.Routing, + }) } - return irouting.Tiered{ - Tiered: routinghelpers.Tiered{ - Routers: irouters, - Validator: in.Validator, - }, - } + return routinghelpers.NewComposableParallel(cRouters) } // OfflineRouting provides a special Router to the routers list when we are creating a offline node. diff --git a/core/node/libp2p/routingopt.go b/core/node/libp2p/routingopt.go index 2e0ac4ab6..262501c69 100644 --- a/core/node/libp2p/routingopt.go +++ b/core/node/libp2p/routingopt.go @@ -2,7 +2,10 @@ package libp2p import ( "context" + "github.com/ipfs/go-datastore" + "github.com/ipfs/kubo/config" + irouting "github.com/ipfs/kubo/routing" dht "github.com/libp2p/go-libp2p-kad-dht" dual "github.com/libp2p/go-libp2p-kad-dht/dual" record "github.com/libp2p/go-libp2p-record" @@ -46,6 +49,36 @@ func constructDHTRouting(mode dht.ModeOpt) func( } } +func ConstructDelegatedRouting(routers config.Routers, methods config.Methods, peerID string, addrs []string, privKey string) func( + ctx context.Context, + host host.Host, + dstore datastore.Batching, + validator record.Validator, + bootstrapPeers ...peer.AddrInfo, +) (routing.Routing, error) { + return func( + ctx context.Context, + host host.Host, + dstore datastore.Batching, + validator record.Validator, + bootstrapPeers ...peer.AddrInfo, + ) (routing.Routing, error) { + return irouting.Parse(routers, methods, + &irouting.ExtraDHTParams{ + BootstrapPeers: bootstrapPeers, + Host: host, + Validator: validator, + Datastore: dstore, + Context: ctx, + }, + &irouting.ExtraReframeParams{ + PeerID: peerID, + Addrs: addrs, + PrivKeyB64: privKey, + }) + } +} + func constructNilRouting( ctx context.Context, host host.Host, diff --git a/core/node/libp2p/transport.go b/core/node/libp2p/transport.go index f5d166175..d96891df2 100644 --- a/core/node/libp2p/transport.go +++ b/core/node/libp2p/transport.go @@ -6,9 +6,10 @@ import ( "github.com/ipfs/kubo/config" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/metrics" - libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" + quic "github.com/libp2p/go-libp2p/p2p/transport/quic" "github.com/libp2p/go-libp2p/p2p/transport/tcp" "github.com/libp2p/go-libp2p/p2p/transport/websocket" + webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" "go.uber.org/fx" ) @@ -21,7 +22,8 @@ func Transports(tptConfig config.Transports) interface{} { privateNetworkEnabled := pnet.Fprint != nil if tptConfig.Network.TCP.WithDefault(true) { - opts.Opts = append(opts.Opts, libp2p.Transport(tcp.NewTCPTransport)) + // TODO(9290): Make WithMetrics configurable + opts.Opts = append(opts.Opts, libp2p.Transport(tcp.NewTCPTransport, tcp.WithMetrics())) } if tptConfig.Network.Websocket.WithDefault(true) { @@ -30,14 +32,22 @@ func Transports(tptConfig config.Transports) interface{} { if tptConfig.Network.QUIC.WithDefault(!privateNetworkEnabled) { if privateNetworkEnabled { - // QUIC was force enabled while the private network was turned on. - // Fail and tell the user. return opts, fmt.Errorf( - "The QUIC transport does not support private networks. " + - "Please disable Swarm.Transports.Network.QUIC.", + "QUIC transport does not support private networks, please disable Swarm.Transports.Network.QUIC", ) } - opts.Opts = append(opts.Opts, libp2p.Transport(libp2pquic.NewTransport)) + // TODO(9290): Make WithMetrics configurable + opts.Opts = append(opts.Opts, libp2p.Transport(quic.NewTransport, quic.WithMetrics())) + } + + // TODO(9292): Remove the false && to allows it enabled by default + if tptConfig.Network.WebTransport.WithDefault(false && !privateNetworkEnabled) { + if privateNetworkEnabled { + return opts, fmt.Errorf( + "WebTransport transport does not support private networks, please disable Swarm.Transports.Network.WebTransport", + ) + } + opts.Opts = append(opts.Opts, libp2p.Transport(webtransport.New)) } return opts, nil diff --git a/core/node/provider.go b/core/node/provider.go index 52cc0b074..cf625b8c6 100644 --- a/core/node/provider.go +++ b/core/node/provider.go @@ -28,13 +28,13 @@ func ProviderQueue(mctx helpers.MetricsCtx, lc fx.Lifecycle, repo repo.Repo) (*q } // SimpleProvider creates new record provider -func SimpleProvider(mctx helpers.MetricsCtx, lc fx.Lifecycle, queue *q.Queue, rt irouting.TieredRouter) provider.Provider { +func SimpleProvider(mctx helpers.MetricsCtx, lc fx.Lifecycle, queue *q.Queue, rt irouting.ProvideManyRouter) provider.Provider { return simple.NewProvider(helpers.LifecycleCtx(mctx, lc), queue, rt) } // SimpleReprovider creates new reprovider func SimpleReprovider(reproviderInterval time.Duration) interface{} { - return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, rt irouting.TieredRouter, keyProvider simple.KeyChanFunc) (provider.Reprovider, error) { + return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, rt irouting.ProvideManyRouter, keyProvider simple.KeyChanFunc) (provider.Reprovider, error) { return simple.NewReprovider(helpers.LifecycleCtx(mctx, lc), reproviderInterval, rt, keyProvider), nil } } @@ -62,12 +62,7 @@ func SimpleProviderSys(isOnline bool) interface{} { // BatchedProviderSys creates new provider system func BatchedProviderSys(isOnline bool, reprovideInterval string) interface{} { - return func(lc fx.Lifecycle, cr irouting.TieredRouter, q *q.Queue, keyProvider simple.KeyChanFunc, repo repo.Repo) (provider.System, error) { - r := cr.ProvideMany() - if r == nil { - return nil, fmt.Errorf("BatchedProviderSys requires a content router that supports provideMany") - } - + return func(lc fx.Lifecycle, cr irouting.ProvideManyRouter, q *q.Queue, keyProvider simple.KeyChanFunc, repo repo.Repo) (provider.System, error) { reprovideIntervalDuration := kReprovideFrequency if reprovideInterval != "" { dur, err := time.ParseDuration(reprovideInterval) @@ -78,7 +73,7 @@ func BatchedProviderSys(isOnline bool, reprovideInterval string) interface{} { reprovideIntervalDuration = dur } - sys, err := batched.New(r, q, + sys, err := batched.New(cr, q, batched.ReproviderInterval(reprovideIntervalDuration), batched.Datastore(repo.Datastore()), batched.KeyProvider(keyProvider)) diff --git a/docs/changelogs/v0.16.md b/docs/changelogs/v0.16.md new file mode 100644 index 000000000..135ef4252 --- /dev/null +++ b/docs/changelogs/v0.16.md @@ -0,0 +1,553 @@ +# Kubo changelog v0.16 + +## v0.16.0 + +### Overview + +Below is an outline of all that is in this release, so you get a sense of all that's included. + +- [Kubo changelog v0.16](#kubo-changelog-v016) + - [v0.16.0](#v0160) + - [Overview](#overview) + - [🔦 Highlights](#-highlights) + - [🛣️ More configurable delegated routing system](#️-more-configurable-delegated-routing-system) + - [🌍 WebTransport new experimental Transport](#-webtransport-new-experimental-transport) + - [🗃️ Hardened IPNS record verification](#-hardened-ipns-record-verification) + - [🌉 Web Gateways now support _redirects files](#-web-gateways-now-support-_redirects-files) + - [😻 Add files to MFS with ipfs add --to-files](#-add-files-to-mfs-with-ipfs-add---to-files) + - [Changelog](#changelog) + - [Contributors](#contributors) + + +### 🔦 Highlights + + + +#### 🛣️ More configurable delegated routing system + +Since Kubo v0.14.0 [Reframe protocol](https://github.com/ipfs/specs/tree/main/reframe#readme) has been supported as a new routing system. + +Now, we allow to configure several routers working together, so you can have several `reframe` and `dht` routers making queries. You can use the special `parallel` and `sequential` routers to fill your needs. + +Example configuration usage using the [Filecoin Network Indexer](https://docs.cid.contact/filecoin-network-indexer/overview) and the DHT, making first a query to the indexer, and timing out after 3 seconds. + +```console +$ ipfs config Routing.Type --json '"custom"' + +$ ipfs config Routing.Routers.CidContact --json '{ + "Type": "reframe", + "Parameters": { + "Endpoint": "https://cid.contact/reframe" + } +}' + +$ ipfs config Routing.Routers.WanDHT --json '{ + "Type": "dht", + "Parameters": { + "Mode": "auto", + "PublicIPNetwork": true, + "AcceleratedDHTClient": false + } +}' + +$ ipfs config Routing.Routers.ParallelHelper --json '{ + "Type": "parallel", + "Parameters": { + "Routers": [ + { + "RouterName" : "CidContact", + "IgnoreErrors" : true, + "Timeout": "3s" + }, + { + "RouterName" : "WanDHT", + "IgnoreErrors" : false, + "Timeout": "5m", + "ExecuteAfter": "2s" + } + ] + } +}' + +$ ipfs config Routing.Methods --json '{ + "find-peers": { + "RouterName": "ParallelHelper" + }, + "find-providers": { + "RouterName": "ParallelHelper" + }, + "get-ipns": { + "RouterName": "ParallelHelper" + }, + "provide": { + "RouterName": "WanDHT" + }, + "put-ipns": { + "RouterName": "ParallelHelper" + } + }' + +``` + +### 🌍 WebTransport new experimental Transport + +A new feature of [`go-libp2p`](https://github.com/libp2p/go-libp2p/releases/tag/v0.23.0) is [WebTransport](https://github.com/libp2p/go-libp2p/issues/1717). + +For now it is **disabled by default** and considered **experimental**. +If you find issues running it please [report them to us](https://github.com/ipfs/kubo/issues/new). + +In the future Kubo will listen on WebTransport by default for anyone already listening on QUIC addresses. + +WebTransport is a new transport protocol currently under development by the [IETF](https://datatracker.ietf.org/wg/webtrans/about/) and the [W3C](https://www.w3.org/TR/webtransport/), and [already implemented by Chrome](https://caniuse.com/webtransport). +Conceptually, it’s like WebSocket run over QUIC instead of TCP. Most importantly, it allows browsers to establish (secure!) connections to WebTransport servers without the need for CA-signed certificates, +thereby enabling any js-libp2p node running in a browser to connect to any kubo node, with zero manual configuration involved. + +The previous alternative is websocket secure, which require installing a reverse proxy and TLS certificates manually. + +#### How to enable WebTransport + +Thoses steps are temporary and wont be needed once we make it enabled by default. + +1. Enable the WebTransport transport: + `ipfs config Swarm.Transports.Network.WebTransport --json true` +1. Add a listener address for WebTransport to your `Addresses.Swarm` key, for example: + ```json + [ + "/ip4/0.0.0.0/tcp/4001", + "/ip4/0.0.0.0/udp/4001/quic", + "/ip4/0.0.0.0/udp/4002/quic/webtransport" + ] + ``` +1. Restart your daemon to apply the config changes. + +### 🗃️ Hardened IPNS record verification + +Records that do not have a valid IPNS V2 signature, or exceed the max size +limit, will no longer pass verification, and will be ignored by Kubo when +resolving `/ipns/{libp2p-key}` content paths. + +Kubo continues publishing backward-compatible V1+V2 records that can be +resolved by V1-only (go-ipfs <0.9.0) clients. + +More details can be found in _Backward Compatibility_, _Record Creation_, and +_Record Verification_ sections of the [updated IPNS +specification](https://github.com/ipfs/specs/pull/319/files). + +### 🌉 Web Gateways now support `_redirects` files + +This feature enables support for redirects, single-page applications (SPA), +custom 404 pages, and moving to IPFS-backed website hosting +[without breaking existing HTTP links](https://www.w3.org/Provider/Style/URI). + +It is limited to websites hosted in web contexts with unique +[Origins](https://en.wikipedia.org/wiki/Same-origin_policy), such as +[subdomain](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#subdomain-gateway) and +[DNSLink](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#dnslink-gateway) gateways. +Redirect logic is evaluated only if the requested path is not in the DAG. + +See more details and usage examples see +[docs.ipfs.tech: _Redirects, custom 404s, and SPA support_](https://docs.ipfs.tech/how-to/websites-on-ipfs/redirects-and-custom-404s/). + +### 😻 Add files to MFS with `ipfs add --to-files` + +Users no longer need to call `ipfs files cp` after `ipfs add` to create a +reference in [MFS](https://docs.ipfs.tech/concepts/glossary/#mfs), or deal with +low level pins if they do not wish to do so. It is now possible to pass MFS +path in an optional `--to-files` to add data directly to MFS, without creating +a low level pin. + +Before (Kubo <0.16.0): + + +```console +$ ipfs add cat.jpg +QmCID +$ ipfs files cp /ipfs/QmCID /mfs-cats/cat.jpg +$ ipfs pin rm QmCID # removing low level pin, since MFS is protecting from gc +``` + +Kubo 0.16.0 collapses the above steps into one: + +```console +$ ipfs add --pin=false cat.jpg --to-files /mfs-cats/ +``` + +A recursive add to MFS works too (below line will create `/lots-of-cats/` directory in MFS): + +```console +$ ipfs add -r ./lots-of-cats/ --to-files / +``` + +For more information, see `ipfs add --help` and `ipfs files --help`. + +### Changelog + +
+Full Changelog + +- github.com/ipfs/kubo: + - fix: Set default Methods value to nil + - docs: document remaining 0.16.0 features + - docs: add WebTransport docs ([ipfs/kubo#9308](https://github.com/ipfs/kubo/pull/9308)) + - chore: bump version to 0.16.0-rc1 + - fix: ensure hasher is registered when using a hashing function + - feat: add webtransport as an optin transport ([ipfs/kubo#9293](https://github.com/ipfs/kubo/pull/9293)) + - feat(gateway): _redirects file support (#8890) ([ipfs/kubo#8890](https://github.com/ipfs/kubo/pull/8890)) + - docs: fix typo in changelog-v0.16.0.md + - Readme: Rewrite introduction and featureset (#9211) ([ipfs/kubo#9211](https://github.com/ipfs/kubo/pull/9211)) + - feat: Delegated routing with custom configuration. (#9274) ([ipfs/kubo#9274](https://github.com/ipfs/kubo/pull/9274)) + - Add to `ipfs id -h` options (#9229) ([ipfs/kubo#9229](https://github.com/ipfs/kubo/pull/9229)) + - chore: bump go-libp2p v0.23.1 ([ipfs/kubo#9285](https://github.com/ipfs/kubo/pull/9285)) + - feat(cmds/add): --to-files option automates files cp (#8927) ([ipfs/kubo#8927](https://github.com/ipfs/kubo/pull/8927)) + - docs: fix broken ENS DoH example (#9281) ([ipfs/kubo#9281](https://github.com/ipfs/kubo/pull/9281)) + - ([ipfs/kubo#9258](https://github.com/ipfs/kubo/pull/9258)) + - ([ipfs/kubo#9213](https://github.com/ipfs/kubo/pull/9213)) + - docs: small typo in Dockerfile + - feat: ipfs-webui v2.18.1 + - feat: ipfs-webui v2.18.0 (#9262) ([ipfs/kubo#9262](https://github.com/ipfs/kubo/pull/9262)) + - bump go-libp2p v0.22.0 & go1.18&go1.19 ([ipfs/kubo#9244](https://github.com/ipfs/kubo/pull/9244)) + - docs: change windows choco install command to point to go-ipfs + - fix: pass the repo directory into the ignored_commit function + - docs(cmds): daemon: update DHTClient description + - fix(gw): send 200 for empty files + - docs(readme): official vs unofficial packages + - chore: remove Gateway.PathPrefixes + - docs(readme): update Docker section + - docs: fix markdown syntax typo in v0.15's changelog + - chore: Release v0.15.0 ([ipfs/kubo#9236](https://github.com/ipfs/kubo/pull/9236)) + - chore: fix undiallable api and gateway files ([ipfs/kubo#9233](https://github.com/ipfs/kubo/pull/9233)) + - chore: Bump version to 0.16.0-dev +- github.com/ipfs/go-bitswap (v0.9.0 -> v0.10.2): + - chore: release v0.10.2 + - fix: create a copy of the protocol slice in network.processSettings + - chore: release v0.10.1 + - fix: incorrect type in the WithTracer polyfill option + - chore: fix incorrect log message when a bad option is passed + - chore: release v0.10.0 + - chore: update go-libp2p v0.22.0 +- github.com/ipfs/go-cid (v0.2.0 -> v0.3.2): + - chore: release v0.3.2 + - Revert "fix: bring back, but deprecate CodecToStr and Codecs" + - chore: release v0.2.1 + - fix: bring back, but deprecate CodecToStr and Codecs + - run gofmt -s + - bump go.mod to Go 1.18 and run go fix + - chore: release v0.3.0 + - fix: return nil Bytes() if the Cid in undef + - Add MustParse ([ipfs/go-cid#139](https://github.com/ipfs/go-cid/pull/139)) +- github.com/ipfs/go-datastore (v0.5.1 -> v0.6.0): + - Release v0.6.0 (#194) ([ipfs/go-datastore#194](https://github.com/ipfs/go-datastore/pull/194)) + - feat: add Features + datastore scoping + - chore: Fix comment typo (#191) ([ipfs/go-datastore#191](https://github.com/ipfs/go-datastore/pull/191)) +- github.com/ipfs/go-delegated-routing (v0.3.0 -> v0.6.0): + - ([ipfs/go-delegated-routing#53](https://github.com/ipfs/go-delegated-routing/pull/53)) + - ([ipfs/go-delegated-routing#52](https://github.com/ipfs/go-delegated-routing/pull/52)) + - Release v0.5.2 (#50) ([ipfs/go-delegated-routing#50](https://github.com/ipfs/go-delegated-routing/pull/50)) + - Fixed serialisation issue with multiadds (#49) ([ipfs/go-delegated-routing#49](https://github.com/ipfs/go-delegated-routing/pull/49)) + - Upgrade to IPLD `0.18.0` + - Release v0.5.0 (#47) ([ipfs/go-delegated-routing#47](https://github.com/ipfs/go-delegated-routing/pull/47)) + - feat: use GET for FindProviders (#46) ([ipfs/go-delegated-routing#46](https://github.com/ipfs/go-delegated-routing/pull/46)) + - Update provide to take an array of keys, per spec (#45) ([ipfs/go-delegated-routing#45](https://github.com/ipfs/go-delegated-routing/pull/45)) + - ([ipfs/go-delegated-routing#44](https://github.com/ipfs/go-delegated-routing/pull/44)) + - fix: upgrade edelweiss and rerun 'go generate' (#42) ([ipfs/go-delegated-routing#42](https://github.com/ipfs/go-delegated-routing/pull/42)) + - ci: add check to ensure generated files are up-to-date (#41) ([ipfs/go-delegated-routing#41](https://github.com/ipfs/go-delegated-routing/pull/41)) + - Add Provide RPC (#37) ([ipfs/go-delegated-routing#37](https://github.com/ipfs/go-delegated-routing/pull/37)) + - upgrade to go-log/v2 (#34) ([ipfs/go-delegated-routing#34](https://github.com/ipfs/go-delegated-routing/pull/34)) +- github.com/ipfs/go-ipns (v0.1.2 -> v0.3.0): + - fix: require V2 signatures ([ipfs/go-ipns#41](https://github.com/ipfs/go-ipns/pull/41)) + - update go-libp2p to v0.22.0, release v0.2.0 (#39) ([ipfs/go-ipns#39](https://github.com/ipfs/go-ipns/pull/39)) + - use peer.IDFromBytes instead of peer.IDFromString (#38) ([ipfs/go-ipns#38](https://github.com/ipfs/go-ipns/pull/38)) + - sync: update CI config files (#34) ([ipfs/go-ipns#34](https://github.com/ipfs/go-ipns/pull/34)) +- github.com/ipfs/go-pinning-service-http-client (v0.1.1 -> v0.1.2): + - chore: release v0.1.2 + - fix: send up to nanosecond precision + - refactor: cleanup Sprintf for Bearer token + - sync: update CI config files ([ipfs/go-pinning-service-http-client#21](https://github.com/ipfs/go-pinning-service-http-client/pull/21)) +- github.com/ipld/edelweiss (v0.1.4 -> v0.2.0): + - Release v0.2.0 (#60) ([ipld/edelweiss#60](https://github.com/ipld/edelweiss/pull/60)) + - feat: add cachable modifier to methods (#48) ([ipld/edelweiss#48](https://github.com/ipld/edelweiss/pull/48)) + - adding licenses (#52) ([ipld/edelweiss#52](https://github.com/ipld/edelweiss/pull/52)) + - sync: update CI config files ([ipld/edelweiss#56](https://github.com/ipld/edelweiss/pull/56)) + - chore: replace deprecated ioutil with io/os ([ipld/edelweiss#59](https://github.com/ipld/edelweiss/pull/59)) + - Release v0.1.6 + - fix: iterate over BlueMap in deterministic order (#57) ([ipld/edelweiss#57](https://github.com/ipld/edelweiss/pull/57)) + - fix: wrap DAG-JSON serialization error (#55) ([ipld/edelweiss#55](https://github.com/ipld/edelweiss/pull/55)) + - update examples and harness + - upgrade to go-log/v2 (#53) ([ipld/edelweiss#53](https://github.com/ipld/edelweiss/pull/53)) +- github.com/ipld/go-ipld-prime (v0.17.0 -> v0.18.0): + - Prepare v0.18.0 + - feat(bindnode): add a BindnodeRegistry utility (#437) ([ipld/go-ipld-prime#437](https://github.com/ipld/go-ipld-prime/pull/437)) + - feat(bindnode): support full uint64 range + - chore(bindnode): remove typed functions for options + - chore(bindnode): docs and minor tweaks + - feat(bindnode): make Any converters work for List and Map values + - fix(bindnode): shorten converter option names, minor perf improvements + - fix(bindnode): only custom convert AssignNull for Any converter + - feat(bindnode): pass Null on to nullable custom converters + - chore(bindnode): config helper refactor w/ short-circuit + - feat(bindnode): add AddCustomTypeAnyConverter() to handle `Any` fields + - feat(bindnode): add AddCustomTypeXConverter() options for most scalar kinds + - chore(bindnode): back out of reflection for converters + - feat(bindnode): switch to converter functions instead of type + - feat(bindnode): allow custom type conversions with options + - feat: add release checklist (#442) ([ipld/go-ipld-prime#442](https://github.com/ipld/go-ipld-prime/pull/442)) +- github.com/libp2p/go-flow-metrics (v0.0.3 -> v0.1.0): + - introduce an API to set a mock clock (#20) ([libp2p/go-flow-metrics#20](https://github.com/libp2p/go-flow-metrics/pull/20)) + - chore: skip slow tests when short testing is specified ([libp2p/go-flow-metrics#16](https://github.com/libp2p/go-flow-metrics/pull/16)) +- github.com/libp2p/go-libp2p (v0.21.0 -> v0.23.2): + - release v0.23.2 (#1781) ([libp2p/go-libp2p#1781](https://github.com/libp2p/go-libp2p/pull/1781)) + - webtransport: return error before wrapping opened / accepted streams (#1775) ([libp2p/go-libp2p#1775](https://github.com/libp2p/go-libp2p/pull/1775)) + - release v0.23.1 (#1773) ([libp2p/go-libp2p#1773](https://github.com/libp2p/go-libp2p/pull/1773)) + - websocket: fix nil pointer in tlsClientConf (#1770) ([libp2p/go-libp2p#1770](https://github.com/libp2p/go-libp2p/pull/1770)) + - release v0.23.0 (#1764) ([libp2p/go-libp2p#1764](https://github.com/libp2p/go-libp2p/pull/1764)) + - noise: switch to proto2, use the new NoiseExtensions protobuf ([libp2p/go-libp2p#1762](https://github.com/libp2p/go-libp2p/pull/1762)) + - webtransport: add custom resolver to add SNI (#1761) ([libp2p/go-libp2p#1761](https://github.com/libp2p/go-libp2p/pull/1761)) + - swarm: skip dialing WebTransport addresses when we have QUIC addresses (#1756) ([libp2p/go-libp2p#1756](https://github.com/libp2p/go-libp2p/pull/1756)) + - webtransport: have the server send the certificates (#1757) ([libp2p/go-libp2p#1757](https://github.com/libp2p/go-libp2p/pull/1757)) + - noise: make it possible for the server to send early data (#1750) ([libp2p/go-libp2p#1750](https://github.com/libp2p/go-libp2p/pull/1750)) + - swarm: fix selection of transport for dialing (#1653) ([libp2p/go-libp2p#1653](https://github.com/libp2p/go-libp2p/pull/1653)) + - autorelay: Add a context.Context to WithPeerSource callback (#1736) ([libp2p/go-libp2p#1736](https://github.com/libp2p/go-libp2p/pull/1736)) + - webtransport: add and check the ?type=noise URL parameter (#1749) ([libp2p/go-libp2p#1749](https://github.com/libp2p/go-libp2p/pull/1749)) + - webtransport: disable HTTP origin check (#1752) ([libp2p/go-libp2p#1752](https://github.com/libp2p/go-libp2p/pull/1752)) + - noise: don't fail handshake when early data is received without handler (#1746) ([libp2p/go-libp2p#1746](https://github.com/libp2p/go-libp2p/pull/1746)) + - Add Resolver interface to transport (#1719) ([libp2p/go-libp2p#1719](https://github.com/libp2p/go-libp2p/pull/1719)) + - use new /libp2p/go-libp2p/core pkg (#1745) ([libp2p/go-libp2p#1745](https://github.com/libp2p/go-libp2p/pull/1745)) + - yamux: pass constructors for peer resource scopes to session constructor (#1739) ([libp2p/go-libp2p#1739](https://github.com/libp2p/go-libp2p/pull/1739)) + - tcp: add an option to enable metrics (disabled by default) (#1734) ([libp2p/go-libp2p#1734](https://github.com/libp2p/go-libp2p/pull/1734)) + - move go-libp2p-webtransport to p2p/transport/webtransport ([libp2p/go-libp2p#1737](https://github.com/libp2p/go-libp2p/pull/1737)) + - autorelay: fix race condition in TestBackoff (#1731) ([libp2p/go-libp2p#1731](https://github.com/libp2p/go-libp2p/pull/1731)) + - rcmgr: increase default connection memory limit to 32 MB (#1740) ([libp2p/go-libp2p#1740](https://github.com/libp2p/go-libp2p/pull/1740)) + - quic: update quic-go to v0.29.0 (#1723) ([libp2p/go-libp2p#1723](https://github.com/libp2p/go-libp2p/pull/1723)) + - noise: implement an API to send and receive early data ([libp2p/go-libp2p#1728](https://github.com/libp2p/go-libp2p/pull/1728)) + - identify: make the protocol version configurable (#1724) ([libp2p/go-libp2p#1724](https://github.com/libp2p/go-libp2p/pull/1724)) + - Fix threshold calculation (#1722) ([libp2p/go-libp2p#1722](https://github.com/libp2p/go-libp2p/pull/1722)) + - connmgr: use clock interface (#1720) ([libp2p/go-libp2p#1720](https://github.com/libp2p/go-libp2p/pull/1720)) + - quic: increase the buffer size used for encoding qlogs (#1715) ([libp2p/go-libp2p#1715](https://github.com/libp2p/go-libp2p/pull/1715)) + - quic: add a WithMetrics option (#1716) ([libp2p/go-libp2p#1716](https://github.com/libp2p/go-libp2p/pull/1716)) + - add default listen addresses for QUIC (#1615) ([libp2p/go-libp2p#1615](https://github.com/libp2p/go-libp2p/pull/1615)) + - feat: inject DNS resolver (#1607) ([libp2p/go-libp2p#1607](https://github.com/libp2p/go-libp2p/pull/1607)) + - connmgr: prefer peers with no streams when closing connections (#1675) ([libp2p/go-libp2p#1675](https://github.com/libp2p/go-libp2p/pull/1675)) + - quic: add DisableReuseport option (#1476) ([libp2p/go-libp2p#1476](https://github.com/libp2p/go-libp2p/pull/1476)) + - release v0.22.0 ([libp2p/go-libp2p#1688](https://github.com/libp2p/go-libp2p/pull/1688)) + - fix: don't prefer local ports from other addresses when dialing (#1673) ([libp2p/go-libp2p#1673](https://github.com/libp2p/go-libp2p/pull/1673)) + - crypto: add better support for alternative backends (#1686) ([libp2p/go-libp2p#1686](https://github.com/libp2p/go-libp2p/pull/1686)) + - crypto/secp256k1: Remove btcsuite intermediary. (#1689) ([libp2p/go-libp2p#1689](https://github.com/libp2p/go-libp2p/pull/1689)) + - Update resource manager README (#1684) ([libp2p/go-libp2p#1684](https://github.com/libp2p/go-libp2p/pull/1684)) + - move go-libp2p-core here ([libp2p/go-libp2p#1683](https://github.com/libp2p/go-libp2p/pull/1683)) + - rcmgr: make scaling changes more intuitive (#1685) ([libp2p/go-libp2p#1685](https://github.com/libp2p/go-libp2p/pull/1685)) + - move go-eventbus here ([libp2p/go-libp2p#1681](https://github.com/libp2p/go-libp2p/pull/1681)) + - basichost: remove usage of MultistreamServerMatcher in test (#1680) ([libp2p/go-libp2p#1680](https://github.com/libp2p/go-libp2p/pull/1680)) + - sync: update CI config files (#1678) ([libp2p/go-libp2p#1678](https://github.com/libp2p/go-libp2p/pull/1678)) + - move go-libp2p-resource-manager to p2p/host/resource-manager ([libp2p/go-libp2p#1677](https://github.com/libp2p/go-libp2p/pull/1677)) + - chore: preallocate slices with known final size (#1679) ([libp2p/go-libp2p#1679](https://github.com/libp2p/go-libp2p/pull/1679)) + - autorelay: fix flaky TestMaxAge (#1676) ([libp2p/go-libp2p#1676](https://github.com/libp2p/go-libp2p/pull/1676)) + - move go-libp2p-peerstore to p2p/host/peerstore ([libp2p/go-libp2p#1667](https://github.com/libp2p/go-libp2p/pull/1667)) + - examples: remove ipfs components from echo (#1672) ([libp2p/go-libp2p#1672](https://github.com/libp2p/go-libp2p/pull/1672)) + - chore: update libp2p to v0.21 in examples (#1674) ([libp2p/go-libp2p#1674](https://github.com/libp2p/go-libp2p/pull/1674)) + - change the default key type to Ed25519 (#1576) ([libp2p/go-libp2p#1576](https://github.com/libp2p/go-libp2p/pull/1576)) + - autorelay: poll for new candidates when needed ([libp2p/go-libp2p#1587](https://github.com/libp2p/go-libp2p/pull/1587)) + - examples: fix unresponsive pubsub chat example (#1652) ([libp2p/go-libp2p#1652](https://github.com/libp2p/go-libp2p/pull/1652)) + - routed: respect force direct dial context (#1665) ([libp2p/go-libp2p#1665](https://github.com/libp2p/go-libp2p/pull/1665)) + - pstoremanager: fix flaky TestClose (#1649) ([libp2p/go-libp2p#1649](https://github.com/libp2p/go-libp2p/pull/1649)) + - Allow adding prologue to noise connections (#1663) ([libp2p/go-libp2p#1663](https://github.com/libp2p/go-libp2p/pull/1663)) + - connmgr: add nowatchdog go build tag (#1666) ([libp2p/go-libp2p#1666](https://github.com/libp2p/go-libp2p/pull/1666)) + - mdns: don't discover ourselves (#1661) ([libp2p/go-libp2p#1661](https://github.com/libp2p/go-libp2p/pull/1661)) + - Support generating custom x509 certificates (#1481) ([libp2p/go-libp2p#1481](https://github.com/libp2p/go-libp2p/pull/1481)) +- github.com/libp2p/go-libp2p-core (v0.19.1 -> v0.20.1): + - chore: release v0.20.1 + - feat: forward crypto/pb + - release v0.20.0 + - deprecate this repo + - stop using the deprecated io/ioutil package (#279) ([libp2p/go-libp2p-core#279](https://github.com/libp2p/go-libp2p-core/pull/279)) + - use a mock clock in bandwidth tests (#276) ([libp2p/go-libp2p-core#276](https://github.com/libp2p/go-libp2p-core/pull/276)) + - remove unused MultistreamSemverMatcher (#277) ([libp2p/go-libp2p-core#277](https://github.com/libp2p/go-libp2p-core/pull/277)) + - remove peer.IDFromString (#274) ([libp2p/go-libp2p-core#274](https://github.com/libp2p/go-libp2p-core/pull/274)) + - deprecate peer.Encode in favor of peer.ID.String (#275) ([libp2p/go-libp2p-core#275](https://github.com/libp2p/go-libp2p-core/pull/275)) + - deprecate peer.ID.Pretty (#273) ([libp2p/go-libp2p-core#273](https://github.com/libp2p/go-libp2p-core/pull/273)) +- github.com/libp2p/go-libp2p-kad-dht (v0.17.0 -> v0.18.0): + - update go-libp2p to v0.22.0, release v0.18.0 ([libp2p/go-libp2p-kad-dht#788](https://github.com/libp2p/go-libp2p-kad-dht/pull/788)) + - sync: update CI config files (#789) ([libp2p/go-libp2p-kad-dht#789](https://github.com/libp2p/go-libp2p-kad-dht/pull/789)) +- github.com/libp2p/go-libp2p-peerstore (v0.7.1 -> v0.8.0): + - release v0.8.0 + - deprecate this repo + - fix flaky TestGCDelay (#206) ([libp2p/go-libp2p-peerstore#206](https://github.com/libp2p/go-libp2p-peerstore/pull/206)) + - fix flaky EWMA test (#205) ([libp2p/go-libp2p-peerstore#205](https://github.com/libp2p/go-libp2p-peerstore/pull/205)) +- github.com/libp2p/go-libp2p-record (v0.1.3 -> v0.2.0): + - update go-libp2p to v0.22.0, release v0.2.0 ([libp2p/go-libp2p-record#50](https://github.com/libp2p/go-libp2p-record/pull/50)) + - sync: update CI config files (#47) ([libp2p/go-libp2p-record#47](https://github.com/libp2p/go-libp2p-record/pull/47)) + - increase RSA key sizes in tests ([libp2p/go-libp2p-record#44](https://github.com/libp2p/go-libp2p-record/pull/44)) + - cleanup: fix staticcheck failures ([libp2p/go-libp2p-record#43](https://github.com/libp2p/go-libp2p-record/pull/43)) +- github.com/libp2p/go-libp2p-routing-helpers (v0.2.3 -> v0.4.0): + - ([libp2p/go-libp2p-routing-helpers#62](https://github.com/libp2p/go-libp2p-routing-helpers/pull/62)) + - ([libp2p/go-libp2p-routing-helpers#58](https://github.com/libp2p/go-libp2p-routing-helpers/pull/58)) + - Update version.json ([libp2p/go-libp2p-routing-helpers#60](https://github.com/libp2p/go-libp2p-routing-helpers/pull/60)) + - update go-libp2p to v0.22.0 ([libp2p/go-libp2p-routing-helpers#59](https://github.com/libp2p/go-libp2p-routing-helpers/pull/59)) + - sync: update CI config files (#53) ([libp2p/go-libp2p-routing-helpers#53](https://github.com/libp2p/go-libp2p-routing-helpers/pull/53)) + - fix staticcheck ([libp2p/go-libp2p-routing-helpers#49](https://github.com/libp2p/go-libp2p-routing-helpers/pull/49)) + - fix error handling in Parallel.search ([libp2p/go-libp2p-routing-helpers#48](https://github.com/libp2p/go-libp2p-routing-helpers/pull/48)) +- github.com/libp2p/go-libp2p-testing (v0.11.0 -> v0.12.0): + - release v0.12.0 (#67) ([libp2p/go-libp2p-testing#67](https://github.com/libp2p/go-libp2p-testing/pull/67)) + - chore: update to go-libp2p v0.22.0 (#66) ([libp2p/go-libp2p-testing#66](https://github.com/libp2p/go-libp2p-testing/pull/66)) + - remove the resource manager mocks (#65) ([libp2p/go-libp2p-testing#65](https://github.com/libp2p/go-libp2p-testing/pull/65)) +- github.com/libp2p/go-openssl (v0.0.7 -> v0.1.0): + - release v0.1.0 (#31) ([libp2p/go-openssl#31](https://github.com/libp2p/go-openssl/pull/31)) + - Fix build with OpenSSL 3.0 (#25) ([libp2p/go-openssl#25](https://github.com/libp2p/go-openssl/pull/25)) + - sync: update CI config files ([libp2p/go-openssl#24](https://github.com/libp2p/go-openssl/pull/24)) + - Add openssl.DialTimeout(network, addr, timeout, ctx, flags) call ([libp2p/go-openssl#26](https://github.com/libp2p/go-openssl/pull/26)) + - Add Ctx.SetMinProtoVersion and Ctx.SetMaxProtoVersion wrappers ([libp2p/go-openssl#27](https://github.com/libp2p/go-openssl/pull/27)) + - sync: update CI config files ([libp2p/go-openssl#17](https://github.com/libp2p/go-openssl/pull/17)) + - fix: unsafe pointer passing ([libp2p/go-openssl#18](https://github.com/libp2p/go-openssl/pull/18)) + - Update test RSA cert ([libp2p/go-openssl#15](https://github.com/libp2p/go-openssl/pull/15)) + - Fix tests ([libp2p/go-openssl#16](https://github.com/libp2p/go-openssl/pull/16)) + - Address `staticcheck` issues ([libp2p/go-openssl#14](https://github.com/libp2p/go-openssl/pull/14)) + - Enabled PEM files with CRLF line endings to be used (#10) ([libp2p/go-openssl#11](https://github.com/libp2p/go-openssl/pull/11)) +- github.com/libp2p/zeroconf/v2 (v2.1.1 -> v2.2.0): + - Fix windows libp2p (#29) ([libp2p/zeroconf#29](https://github.com/libp2p/zeroconf/pull/29)) + - Fix compatibility with some IoT devices using avahi 0.8-rc1 (#27) ([libp2p/zeroconf#27](https://github.com/libp2p/zeroconf/pull/27)) + - Add TTL server option (#23) ([libp2p/zeroconf#23](https://github.com/libp2p/zeroconf/pull/23)) +- github.com/lucas-clemente/quic-go (v0.28.0 -> v0.29.1): + - http3: fix double close of chan when using DontCloseRequestStream + - add a logging.NullTracer and logging.NullConnectionTracer ([lucas-clemente/quic-go#3512](https://github.com/lucas-clemente/quic-go/pull/3512)) + - add support for providing a custom Connection ID generator via Config (#3452) ([lucas-clemente/quic-go#3452](https://github.com/lucas-clemente/quic-go/pull/3452)) + - fix typo in README + - fix datagram support detection (#3511) ([lucas-clemente/quic-go#3511](https://github.com/lucas-clemente/quic-go/pull/3511)) + - use a single Go routine to send copies of CONNECTION_CLOSE packets ([lucas-clemente/quic-go#3514](https://github.com/lucas-clemente/quic-go/pull/3514)) + - add YoMo to list of projects in README (#3513) ([lucas-clemente/quic-go#3513](https://github.com/lucas-clemente/quic-go/pull/3513)) + - http3: fix listening on both QUIC and TCP (#3465) ([lucas-clemente/quic-go#3465](https://github.com/lucas-clemente/quic-go/pull/3465)) + - Disable anti-amplification limit by address validation token (#3326) ([lucas-clemente/quic-go#3326](https://github.com/lucas-clemente/quic-go/pull/3326)) + - fix typo in README + - implement a new API to let servers control client address verification ([lucas-clemente/quic-go#3501](https://github.com/lucas-clemente/quic-go/pull/3501)) + - use a generic streams map for incoming streams ([lucas-clemente/quic-go#3489](https://github.com/lucas-clemente/quic-go/pull/3489)) + - fix unreachable code after log.Fatal in fuzzing corpus generator (#3496) ([lucas-clemente/quic-go#3496](https://github.com/lucas-clemente/quic-go/pull/3496)) + - use generic Min and Max functions ([lucas-clemente/quic-go#3483](https://github.com/lucas-clemente/quic-go/pull/3483)) + - add QPACK (RFC 9204) to the list of supported RFCs (#3485) ([lucas-clemente/quic-go#3485](https://github.com/lucas-clemente/quic-go/pull/3485)) + - add a function to distinguish between long and short header packets (#3498) ([lucas-clemente/quic-go#3498](https://github.com/lucas-clemente/quic-go/pull/3498)) + - use a generic streams map for outgoing streams (#3488) ([lucas-clemente/quic-go#3488](https://github.com/lucas-clemente/quic-go/pull/3488)) + - update golangci-lint action to v3, golangci-lint to v1.48.0 (#3499) ([lucas-clemente/quic-go#3499](https://github.com/lucas-clemente/quic-go/pull/3499)) + - use a generic linked list (#3487) ([lucas-clemente/quic-go#3487](https://github.com/lucas-clemente/quic-go/pull/3487)) + - drop support for Go 1.16 and 1.17 (#3482) ([lucas-clemente/quic-go#3482](https://github.com/lucas-clemente/quic-go/pull/3482)) + - optimize FirstOutstanding in the sent packet history (#3467) ([lucas-clemente/quic-go#3467](https://github.com/lucas-clemente/quic-go/pull/3467)) + - update supported RFCs in README (#3456) ([lucas-clemente/quic-go#3456](https://github.com/lucas-clemente/quic-go/pull/3456)) + - http3: ignore context after response when using DontCloseRequestStream (#3473) ([lucas-clemente/quic-go#3473](https://github.com/lucas-clemente/quic-go/pull/3473)) +- github.com/marten-seemann/webtransport-go (null -> v0.1.1): + - release v0.1.1 (#31) ([marten-seemann/webtransport-go#31](https://github.com/marten-seemann/webtransport-go/pull/31)) + - fix double close of chan when using DontCloseRequestStream +- github.com/multiformats/go-base32 (v0.0.4 -> v0.1.0): + - chore: bump version to 0.1.0 + - fix: fix staticcheck complaints + - run gofmt -s + - sync: update CI config files (#5) ([multiformats/go-base32#5](https://github.com/multiformats/go-base32/pull/5)) +- github.com/multiformats/go-multiaddr (v0.6.0 -> v0.7.0): + - Release v0.7.0 ([multiformats/go-multiaddr#183](https://github.com/multiformats/go-multiaddr/pull/183)) + - use decimal numbers for multicodecs ([multiformats/go-multiaddr#184](https://github.com/multiformats/go-multiaddr/pull/184)) + - Fix comment on Decapsulate ([multiformats/go-multiaddr#181](https://github.com/multiformats/go-multiaddr/pull/181)) + - ([multiformats/go-multiaddr#182](https://github.com/multiformats/go-multiaddr/pull/182)) + - sync: update CI config files (#180) ([multiformats/go-multiaddr#180](https://github.com/multiformats/go-multiaddr/pull/180)) + - Add webrtc (#179) ([multiformats/go-multiaddr#179](https://github.com/multiformats/go-multiaddr/pull/179)) +- github.com/multiformats/go-multicodec (v0.5.0 -> v0.6.0): + - chore: version bump 0.6.0 + - fix: replace io/ioutil with io + - bump go.mod to Go 1.18 and run go fix + +
+ +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Marten Seemann | 236 | +12637/-24326 | 1152 | +| Raúl Kripalani | 118 | +11626/-4136 | 422 | +| vyzo | 144 | +10129/-3665 | 230 | +| galargh | 9 | +5293/-5298 | 26 | +| Marco Munizaga | 83 | +7502/-3080 | 147 | +| Antonio Navarro Perez | 33 | +4074/-1240 | 78 | +| Steven Allen | 98 | +1974/-1693 | 202 | +| Cole Brown | 57 | +2169/-1338 | 95 | +| Rod Vagg | 21 | +2588/-768 | 56 | +| Gus Eggert | 16 | +2011/-1226 | 36 | +| Yusef Napora | 6 | +2738/-187 | 43 | +| Raúl Kripalani | 2 | +1000/-889 | 18 | +| Łukasz Magiera | 26 | +1312/-500 | 54 | +| Will | 2 | +1593/-200 | 18 | +| Jorropo | 31 | +924/-712 | 204 | +| Juan Batiz-Benet | 2 | +1531/-9 | 21 | +| Jeromy | 14 | +691/-468 | 51 | +| Petar Maymounkov | 4 | +469/-285 | 25 | +| Jeromy Johnson | 24 | +474/-204 | 116 | +| Justin Johnson | 1 | +582/-93 | 7 | +| Aarsh Shah | 24 | +377/-105 | 34 | +| web3-bot | 18 | +246/-228 | 93 | +| Masih H. Derkani | 2 | +197/-213 | 21 | +| Marcin Rataj | 9 | +211/-176 | 16 | +| adam | 4 | +235/-49 | 9 | +| Jakub Sztandera | 9 | +203/-73 | 13 | +| Guilhem Fanton | 1 | +216/-48 | 5 | +| Lucas Molas | 1 | +219/-9 | 3 | +| Peter Argue | 1 | +166/-36 | 3 | +| Vibhav Pant | 4 | +186/-12 | 7 | +| Adrian Lanzafame | 3 | +180/-16 | 5 | +| Lars Gierth | 5 | +151/-41 | 25 | +| João Oliveirinha | 1 | +124/-38 | 11 | +| dignifiedquire | 3 | +122/-33 | 6 | +| Chinmay Kousik | 2 | +128/-4 | 7 | +| Toby | 1 | +89/-36 | 4 | +| Oleg Jukovec | 3 | +111/-14 | 8 | +| Whyrusleeping | 2 | +120/-0 | 6 | +| KevinZønda | 1 | +81/-20 | 2 | +| wzp | 2 | +86/-3 | 2 | +| Benedikt Spies | 1 | +75/-12 | 8 | +| nisainan | 1 | +33/-43 | 12 | +| Tshaka Eric Lekholoane | 1 | +57/-19 | 6 | +| cpuchip | 1 | +65/-6 | 2 | +| Roman Proskuryakov | 2 | +69/-0 | 2 | +| Arceliar | 2 | +36/-28 | 2 | +| Maxim Merzhanov | 1 | +29/-24 | 1 | +| Richard Ramos | 1 | +51/-0 | 2 | +| Dave Collins | 1 | +25/-25 | 4 | +| Leo Balduf | 2 | +37/-10 | 3 | +| David Aronchick | 1 | +42/-0 | 3 | +| Didrik Nordström | 1 | +35/-6 | 1 | +| Vasco Santos | 1 | +20/-20 | 7 | +| Jesse Bouwman | 1 | +19/-21 | 1 | +| Ivan Schasny | 2 | +22/-14 | 4 | +| MGMCN | 1 | +9/-24 | 2 | +| Brian Meek | 1 | +14/-17 | 4 | +| Ian Davis | 3 | +21/-9 | 5 | +| Mars Zuo | 1 | +7/-18 | 1 | +| RubenKelevra | 1 | +10/-10 | 1 | +| mojatter | 1 | +9/-8 | 1 | +| Cory Schwartz | 1 | +0/-17 | 1 | +| Steve Loeppky | 6 | +7/-6 | 6 | +| Matt Joiner | 2 | +10/-3 | 2 | +| Winterhuman | 2 | +7/-5 | 2 | +| Dmitry Yu Okunev | 1 | +5/-7 | 5 | +| corverroos | 1 | +7/-4 | 2 | +| Marcel Gregoriadis | 1 | +9/-0 | 1 | +| Ignacio Hagopian | 2 | +7/-2 | 2 | +| Julien Muret | 1 | +4/-4 | 2 | +| Eclésio Junior | 1 | +8/-0 | 1 | +| Stephan Eberle | 1 | +4/-3 | 1 | +| muXxer | 1 | +3/-3 | 1 | +| eth-limo | 1 | +3/-3 | 2 | +| Russell Dempsey | 2 | +4/-2 | 2 | +| Sergey | 1 | +1/-3 | 1 | +| Jun10ng | 2 | +2/-2 | 2 | +| Jorik Schellekens | 1 | +2/-2 | 1 | +| Eli Wang | 1 | +2/-2 | 1 | +| Andreas Linde | 1 | +4/-0 | 1 | +| whyrusleeping | 1 | +2/-1 | 1 | +| xiabin | 1 | +1/-1 | 1 | +| star | 1 | +0/-2 | 1 | +| fanweixiao | 1 | +1/-1 | 1 | +| dbadoy4874 | 1 | +1/-1 | 1 | +| bigs | 1 | +1/-1 | 1 | +| Tarun Bansal | 1 | +1/-1 | 1 | +| Mikerah | 1 | +1/-1 | 1 | +| Mike Goelzer | 1 | +2/-0 | 1 | +| Max Inden | 1 | +1/-1 | 1 | +| Kevin Mai-Husan Chia | 1 | +1/-1 | 1 | +| John B Nelson | 1 | +1/-1 | 1 | +| Eli Bailey | 1 | +1/-1 | 1 | +| Bryan Stenson | 1 | +1/-1 | 1 | +| Alex Stokes | 1 | +1/-1 | 1 | +| Abirdcfly | 1 | +1/-1 | 1 | diff --git a/docs/config.md b/docs/config.md index 87232b166..844109a79 100644 --- a/docs/config.md +++ b/docs/config.md @@ -59,6 +59,7 @@ config file at runtime. - [`Gateway.PublicGateways: Paths`](#gatewaypublicgateways-paths) - [`Gateway.PublicGateways: UseSubdomains`](#gatewaypublicgateways-usesubdomains) - [`Gateway.PublicGateways: NoDNSLink`](#gatewaypublicgateways-nodnslink) + - [`Gateway.PublicGateways: InlineDNSLink`](#gatewaypublicgateways-inlinednslink) - [Implicit defaults of `Gateway.PublicGateways`](#implicit-defaults-of-gatewaypublicgateways) - [`Gateway` recipes](#gateway-recipes) - [`Identity`](#identity) @@ -105,8 +106,8 @@ config file at runtime. - [`Routing`](#routing) - [`Routing.Routers`](#routingrouters) - [`Routing.Routers: Type`](#routingrouters-type) - - [`Routing.Routers: Enabled`](#routingrouters-enabled) - [`Routing.Routers: Parameters`](#routingrouters-parameters) + - [`Routing: Methods`](#routing-methods) - [`Routing.Type`](#routingtype) - [`Swarm`](#swarm) - [`Swarm.AddrFilters`](#swarmaddrfilters) @@ -148,6 +149,8 @@ config file at runtime. - [`Swarm.Transports.Network.Websocket`](#swarmtransportsnetworkwebsocket) - [`Swarm.Transports.Network.QUIC`](#swarmtransportsnetworkquic) - [`Swarm.Transports.Network.Relay`](#swarmtransportsnetworkrelay) + - [`Swarm.Transports.Network.WebTransport`](#swarmtransportsnetworkwebtransport) + - [How to enable WebTransport](#how-to-enable-webtransport) - [`Swarm.Transports.Security`](#swarmtransportssecurity) - [`Swarm.Transports.Security.TLS`](#swarmtransportssecuritytls) - [`Swarm.Transports.Security.SECIO`](#swarmtransportssecuritysecio) @@ -205,7 +208,7 @@ documented in `ipfs config profile --help`. Configures the node to use the flatfs datastore. Flatfs is the default datastore. - This is the most battle-tested and reliable datastore. + This is the most battle-tested and reliable datastore. You should use this datastore if: - You need a very simple and very reliable datastore, and you trust your @@ -223,9 +226,9 @@ documented in `ipfs config profile --help`. Configures the node to use the experimental badger datastore. Keep in mind that this **uses an outdated badger 1.x**. - Use this datastore if some aspects of performance, + Use this datastore if some aspects of performance, especially the speed of adding many gigabytes of files, are critical. However, be aware that: - + - This datastore will not properly reclaim space when your datastore is smaller than several gigabytes. If you run IPFS with `--enable-gc`, you plan on storing very little data in your IPFS node, and disk usage is more critical than performance, consider using @@ -358,6 +361,7 @@ Supported Transports: * tcp/ip{4,6} - `/ipN/.../tcp/...` * websocket - `/ipN/.../tcp/.../ws` * quic - `/ipN/.../udp/.../quic` +* webtransport (*experiemental*) - `/ipN/.../udp/.../quic/webtransport` - require using a different port than the QUIC listener for now Default: ```json @@ -764,6 +768,26 @@ Default: `false` (DNSLink lookup enabled by default for every defined hostname) Type: `bool` +#### `Gateway.PublicGateways: InlineDNSLink` + +An optional flag to explicitly configure whether subdomain gateway's redirects +(enabled by `UseSubdomains: true`) should always inline a DNSLink name (FQDN) +into a single DNS label: + +``` +//example.com/ipns/example.net → HTTP 301 → //example-net.ipns.example.com +``` + +DNSLink name inlining allows for HTTPS on public subdomain gateways with single +label wildcard TLS certs (also enabled when passing `X-Forwarded-Proto: https`), +and provides disjoint Origin per root CID when special rules like +https://publicsuffix.org, or a custom localhost logic in browsers like Brave +has to be applied. + +Default: `false` + +Type: `flag` + #### Implicit defaults of `Gateway.PublicGateways` Default entries for `localhost` hostname and loopback IPs are always present. @@ -804,17 +828,17 @@ Below is a list of the most common public gateway setups. }' ``` - **Backward-compatible:** this feature enables automatic redirects from content paths to subdomains: - + `http://dweb.link/ipfs/{cid}` → `http://{cid}.ipfs.dweb.link` - + - **X-Forwarded-Proto:** if you run Kubo behind a reverse proxy that provides TLS, make it add a `X-Forwarded-Proto: https` HTTP header to ensure users are redirected to `https://`, not `http://`. It will also ensure DNSLink names are inlined to fit in a single DNS label, so they work fine with a wildcart TLS cert ([details](https://github.com/ipfs/in-web-browsers/issues/169)). The NGINX directive is `proxy_set_header X-Forwarded-Proto "https";`.: - + `http://dweb.link/ipfs/{cid}` → `https://{cid}.ipfs.dweb.link` - + `http://dweb.link/ipns/your-dnslink.site.example.com` → `https://your--dnslink-site-example-com.ipfs.dweb.link` - + - **X-Forwarded-Host:** we also support `X-Forwarded-Host: example.com` if you want to override subdomain gateway host from the original request: - + `http://dweb.link/ipfs/{cid}` → `http://{cid}.ipfs.example.com` @@ -839,7 +863,7 @@ Below is a list of the most common public gateway setups. Disable fetching of remote data (`NoFetch: true`) and resolving DNSLink at unknown hostnames (`NoDNSLink: true`). Then, enable DNSLink gateway only for the specific hostname (for which data is already present on the node), without exposing any content-addressing `Paths`: - + ```console $ ipfs config --json Gateway.NoFetch true $ ipfs config --json Gateway.NoDNSLink true @@ -871,7 +895,7 @@ Type: `string` (base64 encoded) This section includes internal knobs for various subsystems to allow advanced users with big or private infrastructures to fine-tune some behaviors without the need to recompile Kubo. -**Be aware that making informed change here requires in-depth knowledge and most users should leave these untouched. All knobs listed here are subject to breaking changes between versions.** +**Be aware that making informed change here requires in-depth knowledge and most users should leave these untouched. All knobs listed here are subject to breaking changes between versions.** ### `Internal.Bitswap` @@ -1291,20 +1315,11 @@ It specifies the routing type that will be created. Currently supported types: - `reframe` (delegated routing based on the [reframe protocol](https://github.com/ipfs/specs/tree/main/reframe#readme)) -- `dht` (WIP, custom DHT will be added in a future release) +- `dht` +- `parallel` and `sequential`: Helpers that can be used to run several routers sequentially or in parallel. Type: `string` -#### `Routing.Routers: Enabled` - -**EXPERIMENTAL: `Routing.Routers` configuration may change in future release** - -Optional flag to disable the specified router without removing it from the configuration file. - -Default: `true` - -Type: `flag` (`null`/missing will apply the default) - #### `Routing.Routers: Parameters` **EXPERIMENTAL: `Routing.Routers` configuration may change in future release** @@ -1313,7 +1328,26 @@ Parameters needed to create the specified router. Supported params per router ty Reframe: - `Endpoint` (mandatory): URL that will be used to connect to a specified router. - - `Priority` (optional): Priority is used when making a routing request. Small numbers represent more important routers. The default priority is 100000. + +DHT: + - `"Mode"`: Mode used by the DHT. Possible values: "server", "client", "auto" + - `"AcceleratedDHTClient"`: Set to `true` if you want to use the experimentalDHT. + - `"PublicIPNetwork"`: Set to `true` to create a `WAN` DHT. Set to `false` to create a `LAN` DHT. + +Parallel: + - `Routers`: A list of routers that will be executed in parallel: + - `Name:string`: Name of the router. It should be one of the previously added to `Routers` list. + - `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)` (`10s`, `1m`, `2h`). Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout. + - `ExecuteAfter:duration`: Providing this param will delay the execution of that router at the specified time. It accepts strings compatible with Go `time.ParseDuration(string)` (`10s`, `1m`, `2h`). + - `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred. + - `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)` (`10s`, `1m`, `2h`). + +Sequential: + - `Routers`: A list of routers that will be executed in order: + - `Name:string`: Name of the router. It should be one of the previously added to `Routers` list. + - `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout. + - `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred. + - `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. **Examples:** @@ -1334,13 +1368,106 @@ Default: `{}` (use the safe implicit defaults) Type: `object[string->string]` +### `Routing: Methods` + +`Methods:map` will define which routers will be executed per method. The key will be the name of the method: `"provide"`, `"find-providers"`, `"find-peers"`, `"put-ipns"`, `"get-ipns"`. All methods must be added to the list. + +The value will contain: +- `RouterName:string`: Name of the router. It should be one of the previously added to `Routing.Routers` list. + +Type: `object[string->object]` + +**Examples:** + +To use the previously added `CidContact` reframe router on all methods: + +```console +$ ipfs config Routing.Methods --json '{ + "find-peers": { + "RouterName": "CidContact" + }, + "find-providers": { + "RouterName": "CidContact" + }, + "get-ipns": { + "RouterName": "CidContact" + }, + "provide": { + "RouterName": "CidContact" + }, + "put-ipns": { + "RouterName": "CidContact" + } + }' +``` +Complete example using 3 Routers, reframe, DHT and parallel. + +``` +$ ipfs config Routing.Type --json '"custom"' + +$ ipfs config Routing.Routers.CidContact --json '{ + "Type": "reframe", + "Parameters": { + "Endpoint": "https://cid.contact/reframe" + } +}' + +$ ipfs config Routing.Routers.WanDHT --json '{ + "Type": "dht", + "Parameters": { + "Mode": "auto", + "PublicIPNetwork": true, + "AcceleratedDHTClient": false + } +}' + +$ ipfs config Routing.Routers.ParallelHelper --json '{ + "Type": "parallel", + "Parameters": { + "Routers": [ + { + "RouterName" : "CidContact", + "IgnoreErrors" : true, + "Timeout": "3s" + }, + { + "RouterName" : "WanDHT", + "IgnoreErrors" : false, + "Timeout": "5m", + "ExecuteAfter": "2s" + } + ] + } +}' + +ipfs config Routing.Methods --json '{ + "find-peers": { + "RouterName": "ParallelHelper" + }, + "find-providers": { + "RouterName": "ParallelHelper" + }, + "get-ipns": { + "RouterName": "ParallelHelper" + }, + "provide": { + "RouterName": "WanDHT" + }, + "put-ipns": { + "RouterName": "ParallelHelper" + } + }' + +``` + ### `Routing.Type` -There are two core routing options: "none" and "dht" (default). +There are three core routing options: "none", "dht" (default) and "custom". * If set to "none", your node will use _no_ routing system. You'll have to explicitly connect to peers that have the content you're looking for. * If set to "dht" (or "dhtclient"/"dhtserver"), your node will use the IPFS DHT. +* If set to "custom", `Routing.Routers` will be used. When the DHT is enabled, it can operate in two modes: client and server. @@ -1516,7 +1643,7 @@ Type: `optionalInteger` #### `Swarm.RelayService.ReservationTTL` -Duration of a new or refreshed reservation. +Duration of a new or refreshed reservation. Default: `"1h"` @@ -1755,7 +1882,7 @@ Configuration section for libp2p _network_ transports. Transports enabled in this section will be used for dialing. However, to receive connections on these transports, multiaddrs for these transports must be added to `Addresses.Swarm`. -Supported transports are: QUIC, TCP, WS, and Relay. +Supported transports are: QUIC, TCP, WS, Relay and WebTransport. Each field in this section is a `flag`. @@ -1831,6 +1958,49 @@ Listen Addresses: * This transport is special. Any node that enables this transport can receive inbound connections on this transport, without specifying a listen address. + +#### `Swarm.Transports.Network.WebTransport` + +A new feature of [`go-libp2p`](https://github.com/libp2p/go-libp2p/releases/tag/v0.23.0) +is the [WebTransport](https://github.com/libp2p/go-libp2p/issues/1717) transport. + +This is a spiritual descendant of WebSocket but over `HTTP/3`. +Since this runs on top of `HTTP/3` it uses `QUIC` under the hood. +We expect it to perform worst than `QUIC` because of the extra overhead, +this transport is really meant at agents that cannot do `TCP` or `QUIC` (like browsers). + +For now it is **disabled by default** and considered **experimental**. +If you find issues running it please [report them to us](https://github.com/ipfs/kubo/issues/new). + +In the future Kubo will listen on WebTransport by default for anyone already listening on QUIC addresses. + +WebTransport is a new transport protocol currently under development by the IETF and the W3C, and already implemented by Chrome. +Conceptually, it’s like WebSocket run over QUIC instead of TCP. Most importantly, it allows browsers to establish (secure!) connections to WebTransport servers without the need for CA-signed certificates, +thereby enabling any js-libp2p node running in a browser to connect to any kubo node, with zero manual configuration involved. + +The previous alternative is websocket secure, which require installing a reverse proxy and TLS certificates manually. + +Default: Disabled + +Type: `flag` + + +##### How to enable WebTransport + +Thoses steps are temporary and wont be needed once we make it enabled by default. + +1. Enable the WebTransport transport: + `ipfs config Swarm.Transports.Network.WebTransport --json true` +1. Add a listener address for WebTransport to your `Addresses.Swarm` key, for example: + ```json + [ + "/ip4/0.0.0.0/tcp/4001", + "/ip4/0.0.0.0/udp/4001/quic", + "/ip4/0.0.0.0/udp/4002/quic/webtransport" + ] + ``` +1. Restart your daemon to apply the config changes. + ### `Swarm.Transports.Security` Configuration section for libp2p _security_ transports. Transports enabled in @@ -1928,7 +2098,7 @@ Example: { "DNS": { "Resolvers": { - "eth.": "https://eth.link/dns-query", + "eth.": "https://dns.eth.limo/dns-query", "crypto.": "https://resolver.unstoppable.io/dns-query", "libre.": "https://ns1.iriseden.fr/dns-query", ".": "https://cloudflare-dns.com/dns-query" diff --git a/docs/delegated-routing.md b/docs/delegated-routing.md new file mode 100644 index 000000000..9e2b9c48b --- /dev/null +++ b/docs/delegated-routing.md @@ -0,0 +1,462 @@ +# New multi-router configuration system + +- Start Date: 2022-08-15 +- Related Issues: + - https://github.com/ipfs/kubo/issues/9188 + - https://github.com/ipfs/kubo/issues/9079 + +## Summary + +Previously we only used DHT for content routing and content providing. After kubo-0.14.0 release we added support for [delegated routing using Reframe protocol](https://github.com/ipfs/kubo/pull/8997). + +Now we need a better way to add different routers using different protocols like Reframe or DHT, and be able to configure them to cover different use cases. + +## Motivation + +The actual routing implementation is not enough. Some users needs to have more options when configuring the routing system. The new implementations should be able to: + +- [x] Be user-friendly and easy enough to configure, but also versatile +- [x] Configurable Router execution order + - [x] Delay some of the Router methods execution when they will be executed on parallel +- [x] Configure which method of a giving router will be used +- [x] Mark some router methods as mandatory to make the execution fails if that method fails + +## Detailed design + +### Configuration file description + +The `Routing` configuration section will contain the following keys: + +#### Type + +`Type` will be still in use to avoid complexity for the user that only wants to use Kubo with the default behavior. We are going to add a new type, `custom`, that will use the new router systems. `none` type will deactivate **all** routers, default dht and delegated ones. + +#### Routers + +`Routers` will be a key-value list of routers that will be available to use. The key is the router name and the value is all the needed configurations for that router. the `Type` will define the routing kind. The main router types will be `reframe` and `dht`, but we will implement two special routers used to execute a set of routers in parallel or sequentially: `parallel` router and `sequential` router. + +Depending on the routing type, it will use different parameters: + +##### Reframe + +Params: + +- `"Endpoint"`: URL endpoint implementing Reframe protocol. + +##### DHT + +Params: +- `"Mode"`: Mode used by the DHT. Possible values: "server", "client", "auto" +- `"AcceleratedDHTClient"`: Set to `true` if you want to use the experimentalDHT. +- `"PublicIPNetwork"`: Set to `true` to create a `WAN` DHT. Set to `false` to create a `LAN` DHT. + +##### Parallel + +Params: +- `Routers`: A list of routers that will be executed in parallel: + - `Name:string`: Name of the router. It should be one of the previously added to `Routers` list. + - `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout. + - `ExecuteAfter:duration`: Providing this param will delay the execution of that router at the specified time. It accepts strings compatible with Go `time.ParseDuration(string)`. + - `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred. +- `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. +##### Sequential + +Params: +- `Routers`: A list of routers that will be executed in order: + - `Name:string`: Name of the router. It should be one of the previously added to `Routers` list. + - `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout. + - `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred. +- `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. +#### Methods + +`Methods:map` will define which routers will be executed per method. The key will be the name of the method: `"provide"`, `"find-providers"`, `"find-peers"`, `"put-ipns"`, `"get-ipns"`. All methods must be added to the list. This will make configuration discoverable giving good errors to the user if a method is missing. + +The value will contain: +- `RouterName:string`: Name of the router. It should be one of the previously added to `Routers` list. + +#### Configuration file example: + +```json +"Routing": { + "Type": "custom", + "Routers": { + "storetheindex": { + "Type": "reframe", + "Parameters": { + "Endpoint": "https://cid.contact/reframe" + } + }, + "dht-lan": { + "Type": "dht", + "Parameters": { + "Mode": "server", + "PublicIPNetwork": false, + "AcceleratedDHTClient": false + } + }, + "dht-wan": { + "Type": "dht", + "Parameters": { + "Mode": "auto", + "PublicIPNetwork": true, + "AcceleratedDHTClient": false + } + }, + "find-providers-router": { + "Type": "parallel", + "Parameters": { + "Routers": [ + { + "RouterName": "dht-lan", + "IgnoreErrors": true + }, + { + "RouterName": "dht-wan" + }, + { + "RouterName": "storetheindex" + } + ] + } + }, + "provide-router": { + "Type": "parallel", + "Parameters": { + "Routers": [ + { + "RouterName": "dht-lan", + "IgnoreErrors": true + }, + { + "RouterName": "dht-wan", + "ExecuteAfter": "100ms", + "Timeout": "100ms" + }, + { + "RouterName": "storetheindex", + "ExecuteAfter": "100ms" + } + ] + } + }, + "get-ipns-router": { + "Type": "sequential", + "Parameters": { + "Routers": [ + { + "RouterName": "dht-lan", + "IgnoreErrors": true + }, + { + "RouterName": "dht-wan", + "Timeout": "300ms" + }, + { + "RouterName": "storetheindex", + "Timeout": "300ms" + } + ] + } + }, + "put-ipns-router": { + "Type": "parallel", + "Parameters": { + "Routers": [ + { + "RouterName": "dht-lan" + }, + { + "RouterName": "dht-wan" + }, + { + "RouterName": "storetheindex" + } + ] + } + } + }, + "Methods": { + "find-providers": { + "RouterName": "find-providers-router" + }, + "provide": { + "RouterName": "provide-router" + }, + "get-ipns": { + "RouterName": "get-ipns-router" + }, + "put-ipns": { + "RouterName": "put-ipns-router" + } + } +} +``` + +Added YAML for clarity: + +```yaml +--- +Type: custom +Routers: + storetheindex: + Type: reframe + Parameters: + Endpoint: https://cid.contact/reframe + dht-lan: + Type: dht + Parameters: + Mode: server + PublicIPNetwork: false + AcceleratedDHTClient: false + dht-wan: + Type: dht + Parameters: + Mode: auto + PublicIPNetwork: true + AcceleratedDHTClient: false + find-providers-router: + Type: parallel + Parameters: + Routers: + - RouterName: dht-lan + IgnoreErrors: true + - RouterName: dht-wan + - RouterName: storetheindex + provide-router: + Type: parallel + Parameters: + Routers: + - RouterName: dht-lan + IgnoreErrors: true + - RouterName: dht-wan + ExecuteAfter: 100ms + Timeout: 100ms + - RouterName: storetheindex + ExecuteAfter: 100ms + get-ipns-router: + Type: sequential + Parameters: + Routers: + - RouterName: dht-lan + IgnoreErrors: true + - RouterName: dht-wan + Timeout: 300ms + - RouterName: storetheindex + Timeout: 300ms + put-ipns-router: + Type: parallel + Parameters: + Routers: + - RouterName: dht-lan + - RouterName: dht-wan + - RouterName: storetheindex +Methods: + find-providers: + RouterName: find-providers-router + provide: + RouterName: provide-router + get-ipns: + RouterName: get-ipns-router + put-ipns: + RouterName: put-ipns-router +``` + +### Error cases + - If any of the routers fails, the output will be an error by default. + - You can use `IgnoreErrors:true` to ignore errors for a specific router output + - To avoid any error at the output, you must ignore all router errors. + +### Implementation Details + +#### Methods + +All routers must implement the `routing.Routing` interface: + +```go= +type Routing interface { + ContentRouting + PeerRouting + ValueStore + + Bootstrap(context.Context) error +} +``` + +All methods involved: + +```go= +type Routing interface { + Provide(context.Context, cid.Cid, bool) error + FindProvidersAsync(context.Context, cid.Cid, int) <-chan peer.AddrInfo + + FindPeer(context.Context, peer.ID) (peer.AddrInfo, error) + + PutValue(context.Context, string, []byte, ...Option) error + GetValue(context.Context, string, ...Option) ([]byte, error) + SearchValue(context.Context, string, ...Option) (<-chan []byte, error) + + Bootstrap(context.Context) error +} +``` +We can configure which methods will be used per routing implementation. Methods names used in the configuration file will be: + +- `Provide`: `"provide"` +- `FindProvidersAsync`: `"find-providers"` +- `FindPeer`: `"find-peers"` +- `PutValue`: `"put-ipns"` +- `GetValue`, `SearchValue`: `"get-ipns"` +- `Bootstrap`: It will be always executed when needed. + +#### Routers + +We need to implement the `parallel` and `sequential` routers and stop using `routinghelpers.Tiered` router implementation. + +Add cycle detection to avoid to user some headaches. + +Also we need to implement an internal router, that will define the router used per method. + +#### Other considerations + +- We need to refactor how DHT routers are created to be able to use and add any amount of custom DHT routers. +- We need to add a new `custom` router type to be able to use the new routing system. +- Bitswap WANT broadcasting is not included on this document, but it can be added in next iterations. +- This document will live in docs/design-notes for historical reasons and future reference. + +## Test fixtures + +As test fixtures we can add different use cases here and see how the configuration will look like. + +### Mimic previous dual DHT config + +```json +"Routing": { + "Type": "custom", + "Routers": { + "dht-lan": { + "Type": "dht", + "Parameters": { + "Mode": "server", + "PublicIPNetwork": false + } + }, + "dht-wan": { + "Type": "dht", + "Parameters": { + "Mode": "auto", + "PublicIPNetwork": true + } + }, + "parallel-dht-strict": { + "Type": "parallel", + "Parameters": { + "Routers": [ + { + "RouterName": "dht-lan" + }, + { + "RouterName": "dht-wan" + } + ] + } + }, + "parallel-dht": { + "Type": "parallel", + "Parameters": { + "Routers": [ + { + "RouterName": "dht-lan", + "IgnoreError": true + }, + { + "RouterName": "dht-wan" + } + ] + } + } + }, + "Methods": { + "provide": { + "RouterName": "dht-wan" + }, + "find-providers": { + "RouterName": "parallel-dht-strict" + }, + "find-peers": { + "RouterName": "parallel-dht-strict" + }, + "get-ipns": { + "RouterName": "parallel-dht" + }, + "put-ipns": { + "RouterName": "parallel-dht" + } + } +} +``` + +Yaml representation for clarity: + +```yaml +--- +Type: custom +Routers: + dht-lan: + Type: dht + Parameters: + Mode: server + PublicIPNetwork: false + dht-wan: + Type: dht + Parameters: + Mode: auto + PublicIPNetwork: true + parallel-dht-strict: + Type: parallel + Parameters: + Routers: + - RouterName: dht-lan + - RouterName: dht-wan + parallel-dht: + Type: parallel + Parameters: + Routers: + - RouterName: dht-lan + IgnoreError: true + - RouterName: dht-wan +Methods: + provide: + RouterName: dht-wan + find-providers: + RouterName: parallel-dht-strict + find-peers: + RouterName: parallel-dht-strict + get-ipns: + RouterName: parallel-dht + put-ipns: + RouterName: parallel-dht + +``` + +### Compatibility + +~~We need to create a config migration using [fs-repo-migrations](https://github.com/ipfs/fs-repo-migrations). We should remove the `Routing.Type` param and add the configuration specified [previously](#Mimic-previous-dual-DHT-config).~~ + +We don't need to create any config migration! To avoid to the users the hassle of understanding how the new routing system works, we are gonna keep the old behavior. We will add the Type `custom` to make available the new Routing system. + +### Security + +No new security implications or considerations were found. + +### Alternatives + +I got ideas from all of the following links to create this design document: + +- https://github.com/ipfs/kubo/issues/9079#issuecomment-1211288268 +- https://github.com/ipfs/kubo/issues/9157 +- https://github.com/ipfs/kubo/issues/9079#issuecomment-1205000253 +- https://www.notion.so/pl-strflt/Delegated-Routing-Thoughts-very-very-WIP-0543bc51b1bd4d63a061b0f28e195d38 +- https://gist.github.com/guseggert/effa027ff4cbadd7f67598efb6704d12 + +### Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod index 52b9512a0..886885cc9 100644 --- a/docs/examples/kubo-as-a-library/go.mod +++ b/docs/examples/kubo-as-a-library/go.mod @@ -10,8 +10,8 @@ require ( github.com/ipfs/go-ipfs-files v0.1.1 github.com/ipfs/interface-go-ipfs-core v0.7.0 github.com/ipfs/kubo v0.14.0-rc1 - github.com/libp2p/go-libp2p v0.22.0 - github.com/multiformats/go-multiaddr v0.6.0 + github.com/libp2p/go-libp2p v0.23.2 + github.com/multiformats/go-multiaddr v0.7.0 ) require ( @@ -28,16 +28,15 @@ require ( github.com/ceramicnetwork/go-dag-jose v0.1.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cheekybits/genny v1.0.0 // indirect github.com/containerd/cgroups v1.0.4 // indirect - github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/coreos/go-systemd/v22 v22.4.0 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect github.com/cskr/pubsub v1.0.2 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/dgraph-io/badger v1.6.2 // indirect github.com/dgraph-io/ristretto v0.0.2 // indirect - github.com/docker/go-units v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect @@ -49,6 +48,7 @@ require ( github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect @@ -65,10 +65,10 @@ require ( github.com/ipfs/go-bitswap v0.10.2 // indirect github.com/ipfs/go-block-format v0.0.3 // indirect github.com/ipfs/go-blockservice v0.4.0 // indirect - github.com/ipfs/go-cid v0.3.0 // indirect + github.com/ipfs/go-cid v0.3.2 // indirect github.com/ipfs/go-cidutil v0.1.0 // indirect - github.com/ipfs/go-datastore v0.5.1 // indirect - github.com/ipfs/go-delegated-routing v0.3.0 // indirect + github.com/ipfs/go-datastore v0.6.0 // indirect + github.com/ipfs/go-delegated-routing v0.6.0 // indirect github.com/ipfs/go-ds-badger v0.3.0 // indirect github.com/ipfs/go-ds-flatfs v0.5.1 // indirect github.com/ipfs/go-ds-leveldb v0.5.0 // indirect @@ -94,7 +94,7 @@ require ( github.com/ipfs/go-ipld-format v0.4.0 // indirect github.com/ipfs/go-ipld-git v0.1.1 // indirect github.com/ipfs/go-ipld-legacy v0.1.1 // indirect - github.com/ipfs/go-ipns v0.2.0 // indirect + github.com/ipfs/go-ipns v0.3.0 // indirect github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/ipfs/go-merkledag v0.6.0 // indirect @@ -106,14 +106,14 @@ require ( github.com/ipfs/go-unixfs v0.4.0 // indirect github.com/ipfs/go-unixfsnode v1.4.0 // indirect github.com/ipfs/go-verifcid v0.0.2 // indirect - github.com/ipld/edelweiss v0.1.4 // indirect + github.com/ipld/edelweiss v0.2.0 // indirect github.com/ipld/go-codec-dagpb v1.4.1 // indirect - github.com/ipld/go-ipld-prime v0.17.0 // indirect + github.com/ipld/go-ipld-prime v0.18.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/compress v1.15.1 // indirect - github.com/klauspost/cpuid/v2 v2.1.0 // indirect + github.com/klauspost/compress v1.15.10 // indirect + github.com/klauspost/cpuid/v2 v2.1.1 // indirect github.com/koron/go-ssdp v0.0.3 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect @@ -127,7 +127,7 @@ require ( github.com/libp2p/go-libp2p-pubsub v0.6.1 // indirect github.com/libp2p/go-libp2p-pubsub-router v0.5.0 // indirect github.com/libp2p/go-libp2p-record v0.2.0 // indirect - github.com/libp2p/go-libp2p-routing-helpers v0.2.3 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.4.0 // indirect github.com/libp2p/go-libp2p-xor v0.1.0 // indirect github.com/libp2p/go-mplex v0.7.0 // indirect github.com/libp2p/go-msgio v0.2.0 // indirect @@ -135,14 +135,14 @@ require ( github.com/libp2p/go-netroute v0.2.0 // indirect github.com/libp2p/go-openssl v0.1.0 // indirect github.com/libp2p/go-reuseport v0.2.0 // indirect - github.com/libp2p/go-yamux/v3 v3.1.2 // indirect + github.com/libp2p/go-yamux/v4 v4.0.0 // indirect github.com/libp2p/zeroconf/v2 v2.2.0 // indirect - github.com/lucas-clemente/quic-go v0.28.1 // indirect - github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect - github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect + github.com/lucas-clemente/quic-go v0.29.1 // indirect + github.com/marten-seemann/qpack v0.2.1 // indirect github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect + github.com/marten-seemann/webtransport-go v0.1.1 // indirect github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-pointer v0.0.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect @@ -152,12 +152,12 @@ require ( github.com/minio/sha256-simd v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect - github.com/multiformats/go-base32 v0.0.4 // indirect + github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.1.1 // indirect - github.com/multiformats/go-multicodec v0.5.0 // indirect + github.com/multiformats/go-multicodec v0.6.0 // indirect github.com/multiformats/go-multihash v0.2.1 // indirect github.com/multiformats/go-multistream v0.3.3 // indirect github.com/multiformats/go-varint v0.0.6 // indirect @@ -169,7 +169,7 @@ require ( github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect - github.com/prometheus/client_golang v1.12.1 // indirect + github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect @@ -204,13 +204,14 @@ require ( go.uber.org/dig v1.14.1 // indirect go.uber.org/fx v1.17.1 // indirect go.uber.org/multierr v1.8.0 // indirect - go.uber.org/zap v1.22.0 // indirect + go.uber.org/zap v1.23.0 // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect + golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect + golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect + golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.12 // indirect golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum index 8c56c8e32..b3f5b6f43 100644 --- a/docs/examples/kubo-as-a-library/go.sum +++ b/docs/examples/kubo-as-a-library/go.sum @@ -132,7 +132,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -166,8 +165,9 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU= +github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -203,8 +203,9 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -476,8 +477,9 @@ github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqg github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o= github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= -github.com/ipfs/go-cid v0.3.0 h1:gT6Cbs6YePaBNc7l6v5EXt0xTMup1jGV5EU1N+QLVpY= github.com/ipfs/go-cid v0.3.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= +github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc= +github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw= github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s= github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q= github.com/ipfs/go-cidutil v0.1.0/go.mod h1:e7OEVBMIv9JaOxt9zaGEmAoSlXW9jdFZ5lP/0PwcfpA= @@ -491,10 +493,11 @@ github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13X github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= -github.com/ipfs/go-datastore v0.5.1 h1:WkRhLuISI+XPD0uk3OskB0fYFSyqK8Ob5ZYew9Qa1nQ= github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= -github.com/ipfs/go-delegated-routing v0.3.0 h1:pF5apOJ/xdQkj22mRahW9GmSuCkgMLparKZWKJBO4CE= -github.com/ipfs/go-delegated-routing v0.3.0/go.mod h1:2w79E1/G9YOaxyJJQgqIFSQaa/GdS2zSATEpK8aJUBM= +github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= +github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= +github.com/ipfs/go-delegated-routing v0.6.0 h1:+M1siyTB2H4mHzEnbWjepQxlmKbapVWdbYLexSDODpg= +github.com/ipfs/go-delegated-routing v0.6.0/go.mod h1:FJjhCChfcWK9z6OXo2jwKKJoxq1JlEWG7YTvwaA7UbI= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= @@ -568,6 +571,7 @@ github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= github.com/ipfs/go-ipfs-provider v0.7.1 h1:eKToBUAb6ZY8iiA6AYVxzW4G1ep67XUaaEBUIYpxhfw= github.com/ipfs/go-ipfs-provider v0.7.1/go.mod h1:QwdDYRYnC5sYGLlOwVDY/0ZB6T3zcMtu+5+GdGeUuw8= +github.com/ipfs/go-ipfs-redirects-file v0.1.1/go.mod h1:tAwRjCV0RjLTjH8DR/AU7VYvfQECg+lpUy2Mdzv7gyk= github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY= @@ -592,8 +596,9 @@ github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2cdcc= github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.1.2/go.mod h1:ioQ0j02o6jdIVW+bmi18f4k2gRf0AV3kZ9KeHYHICnQ= -github.com/ipfs/go-ipns v0.2.0 h1:BgmNtQhqOw5XEZ8RAfWEpK4DhqaYiuP6h71MhIp7xXU= github.com/ipfs/go-ipns v0.2.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= +github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A= +github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= @@ -650,8 +655,8 @@ github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0 github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPmI+GksBlLE8js= github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY= github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM= -github.com/ipld/edelweiss v0.1.4 h1:g4+C2Ph+8SV2MCJBG3oRtetvxJYAS2WzlNGgsOY95iM= -github.com/ipld/edelweiss v0.1.4/go.mod h1:JX1MR06BPcTOF+5xCYDLnylYkXS15iUN0/RXVSiUIQs= +github.com/ipld/edelweiss v0.2.0 h1:KfAZBP8eeJtrLxLhi7r3N0cBCo7JmwSRhOJp3WSpNjk= +github.com/ipld/edelweiss v0.2.0/go.mod h1:FJAzJRCep4iI8FOFlRriN9n0b7OuX3T/S9++NpBDmA4= github.com/ipld/go-car v0.4.0 h1:U6W7F1aKF/OJMHovnOVdst2cpQE5GhmHibQkAixgNcQ= github.com/ipld/go-car v0.4.0/go.mod h1:Uslcn4O9cBKK9wqHm/cLTFacg6RAPv6LZx2mxd2Ypl4= github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI= @@ -667,8 +672,9 @@ github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHt github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM= github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA= -github.com/ipld/go-ipld-prime v0.17.0 h1:+U2peiA3aQsE7mrXjD2nYZaZrCcakoz2Wge8K42Ld8g= github.com/ipld/go-ipld-prime v0.17.0/go.mod h1:aYcKm5TIvGfY8P3QBKz/2gKcLxzJ1zDaD+o0bOowhgs= +github.com/ipld/go-ipld-prime v0.18.0 h1:xUk7NUBSWHEXdjiOu2sLXouFJOMs0yoYzeI5RAqhYQo= +github.com/ipld/go-ipld-prime v0.18.0/go.mod h1:735yXW548CKrLwVCYXzqx90p5deRJMVVxM9eJ4Qe+qE= github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= @@ -720,13 +726,15 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= +github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0= github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0= +github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -784,8 +792,9 @@ github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= github.com/libp2p/go-libp2p v0.18.0/go.mod h1:+veaZ9z1SZQhmc5PW78jvnnxZ89Mgvmh4cggO11ETmw= github.com/libp2p/go-libp2p v0.20.0/go.mod h1:g0C5Fu+aXXbCXkusCzLycuBowEih3ElmDqtbo61Em7k= -github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw= github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4= +github.com/libp2p/go-libp2p v0.23.2 h1:yqyTeKQJyofWXxEv/eEVUvOrGdt/9x+0PIQ4N1kaxmE= +github.com/libp2p/go-libp2p v0.23.2/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= @@ -939,8 +948,9 @@ github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvN github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y= github.com/libp2p/go-libp2p-resource-manager v0.3.0/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= -github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY= github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= +github.com/libp2p/go-libp2p-routing-helpers v0.4.0 h1:b7y4aixQ7AwbqYfcOQ6wTw8DQvuRZeTAA0Od3YYN5yc= +github.com/libp2p/go-libp2p-routing-helpers v0.4.0/go.mod h1:dYEAgkVhqho3/YKxfOEGdFMIcWfAFNlZX8iAIihYA2E= github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0= github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= @@ -1110,8 +1120,9 @@ github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDY github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= github.com/libp2p/go-yamux/v3 v3.1.1/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= -github.com/libp2p/go-yamux/v3 v3.1.2 h1:lNEy28MBk1HavUAlzKgShp+F6mn/ea1nDYWftZhFW9Q= github.com/libp2p/go-yamux/v3 v3.1.2/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= +github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= +github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= @@ -1123,25 +1134,25 @@ github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2 github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= github.com/lucas-clemente/quic-go v0.27.1/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= -github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU= github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0= +github.com/lucas-clemente/quic-go v0.29.1 h1:Z+WMJ++qMLhvpFkRZA+jl3BTxUjm415YBmWanXB8zP0= +github.com/lucas-clemente/quic-go v0.29.1/go.mod h1:CTcNfLYJS2UuRNB+zcNlgvkjBhxX6Hm3WUxxAQx2mgE= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs= github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-15 v0.1.5/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= -github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= -github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ= github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= @@ -1152,6 +1163,8 @@ github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= +github.com/marten-seemann/webtransport-go v0.1.1 h1:TnyKp3pEXcDooTaNn4s9dYpMJ7kMnTp7k5h+SgYP/mc= +github.com/marten-seemann/webtransport-go v0.1.1/go.mod h1:kBEh5+RSvOA4troP1vyOVBWK4MIMzDICXVrvCPrYcrM= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -1216,8 +1229,9 @@ github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= @@ -1234,8 +1248,9 @@ github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9x github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc= github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug= -github.com/multiformats/go-multiaddr v0.6.0 h1:qMnoOPj2s8xxPU5kZ57Cqdr0hHhARz7mFsPMIiYNqzg= github.com/multiformats/go-multiaddr v0.6.0/go.mod h1:F4IpaKZuPP360tOMn2Tpyu0At8w23aRyVqeK0DbFeGM= +github.com/multiformats/go-multiaddr v0.7.0 h1:gskHcdaCyPtp9XskVwtvEeQOG465sCohbQIirSyqxrc= +github.com/multiformats/go-multiaddr v0.7.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= @@ -1262,8 +1277,9 @@ github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaI github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multicodec v0.3.1-0.20211210143421-a526f306ed2c/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= -github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs= github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues= +github.com/multiformats/go-multicodec v0.6.0 h1:KhH2kSuCARyuJraYMFxrNO3DqIaYhOdS039kbhgVwpE= +github.com/multiformats/go-multicodec v0.6.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= @@ -1274,6 +1290,7 @@ github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUj github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= github.com/multiformats/go-multihash v0.0.16/go.mod h1:zhfEIgVnB/rPMfxgFw15ZmGoNaKyNUIE4IWHG/kC+Ag= github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84= +github.com/multiformats/go-multihash v0.2.0/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= @@ -1378,8 +1395,9 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1518,9 +1536,11 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= +github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -1659,8 +1679,9 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0= go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= @@ -1715,8 +1736,9 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 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-20210615023648-acb5c1269671/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 h1:rxKZ2gOnYxjfmakvUUqh9Gyb6KXfrj7JWTxORTYqb0E= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b h1:SCE/18RnFsLrjydh/R/s5EVvHoZprqEQUuoxK8q2Pc4= +golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= 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= @@ -1741,8 +1763,7 @@ golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hM golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1810,8 +1831,9 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 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.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 h1:KafLifaRFIuSJ5C+7CyFJOF9haxKNC1CEIDk8GX6X0k= +golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 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= @@ -1932,8 +1954,9 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/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-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/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= @@ -2009,7 +2032,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2159,6 +2182,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/fuse/ipns/ipns_test.go b/fuse/ipns/ipns_test.go index 06bb0cdfe..51ac9518c 100644 --- a/fuse/ipns/ipns_test.go +++ b/fuse/ipns/ipns_test.go @@ -116,12 +116,12 @@ func setupIpnsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *mountWra } } - coreApi, err := coreapi.NewCoreAPI(node) + coreAPI, err := coreapi.NewCoreAPI(node) if err != nil { t.Fatal(err) } - fs, err := NewFileSystem(node.Context(), coreApi, "", "") + fs, err := NewFileSystem(node.Context(), coreAPI, "", "") if err != nil { t.Fatal(err) } diff --git a/fuse/ipns/ipns_unix.go b/fuse/ipns/ipns_unix.go index e1840d259..c19898919 100644 --- a/fuse/ipns/ipns_unix.go +++ b/fuse/ipns/ipns_unix.go @@ -147,25 +147,25 @@ func CreateRoot(ctx context.Context, ipfs iface.CoreAPI, keys map[string]iface.K } // Attr returns file attributes. -func (*Root) Attr(ctx context.Context, a *fuse.Attr) error { +func (r *Root) Attr(ctx context.Context, a *fuse.Attr) error { log.Debug("Root Attr") a.Mode = os.ModeDir | 0111 // -rw+x return nil } // Lookup performs a lookup under this node. -func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) { +func (r *Root) Lookup(ctx context.Context, name string) (fs.Node, error) { switch name { case "mach_kernel", ".hidden", "._.": // Just quiet some log noise on OS X. return nil, fuse.ENOENT } - if lnk, ok := s.LocalLinks[name]; ok { + if lnk, ok := r.LocalLinks[name]; ok { return lnk, nil } - nd, ok := s.LocalDirs[name] + nd, ok := r.LocalDirs[name] if ok { switch nd := nd.(type) { case *Directory: @@ -179,7 +179,7 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) { // other links go through ipns resolution and are symlinked into the ipfs mountpoint ipnsName := "/ipns/" + name - resolved, err := s.Ipfs.Name().Resolve(ctx, ipnsName) + resolved, err := r.Ipfs.Name().Resolve(ctx, ipnsName) if err != nil { log.Warnf("ipns: namesys resolve error: %s", err) return nil, fuse.ENOENT @@ -189,7 +189,7 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) { return nil, errors.New("invalid path from ipns record") } - return &Link{s.IpfsRoot + "/" + strings.TrimPrefix(resolved.String(), "/ipfs/")}, nil + return &Link{r.IpfsRoot + "/" + strings.TrimPrefix(resolved.String(), "/ipfs/")}, nil } func (r *Root) Close() error { @@ -270,8 +270,8 @@ func (fi *FileNode) Attr(ctx context.Context, a *fuse.Attr) error { } // Lookup performs a lookup under this node. -func (s *Directory) Lookup(ctx context.Context, name string) (fs.Node, error) { - child, err := s.dir.Child(name) +func (d *Directory) Lookup(ctx context.Context, name string) (fs.Node, error) { + child, err := d.dir.Child(name) if err != nil { // todo: make this error more versatile. return nil, fuse.ENOENT @@ -290,8 +290,8 @@ func (s *Directory) Lookup(ctx context.Context, name string) (fs.Node, error) { } // ReadDirAll reads the link structure as directory entries -func (dir *Directory) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - listing, err := dir.dir.List(ctx) +func (d *Directory) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + listing, err := d.dir.List(ctx) if err != nil { return nil, err } @@ -401,8 +401,8 @@ func (fi *File) Forget() { } } -func (dir *Directory) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) { - child, err := dir.dir.Mkdir(req.Name) +func (d *Directory) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) { + child, err := d.dir.Mkdir(req.Name) if err != nil { return nil, err } @@ -451,15 +451,15 @@ func (fi *File) Release(ctx context.Context, req *fuse.ReleaseRequest) error { return fi.fi.Close() } -func (dir *Directory) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) { +func (d *Directory) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) { // New 'empty' file nd := dag.NodeWithData(ft.FilePBData(nil, 0)) - err := dir.dir.AddChild(req.Name, nd) + err := d.dir.AddChild(req.Name, nd) if err != nil { return nil, nil, err } - child, err := dir.dir.Child(req.Name) + child, err := d.dir.Child(req.Name) if err != nil { return nil, nil, err } @@ -483,8 +483,8 @@ func (dir *Directory) Create(ctx context.Context, req *fuse.CreateRequest, resp return nodechild, &File{fi: fd}, nil } -func (dir *Directory) Remove(ctx context.Context, req *fuse.RemoveRequest) error { - err := dir.dir.Unlink(req.Name) +func (d *Directory) Remove(ctx context.Context, req *fuse.RemoveRequest) error { + err := d.dir.Unlink(req.Name) if err != nil { return fuse.ENOENT } @@ -492,13 +492,13 @@ func (dir *Directory) Remove(ctx context.Context, req *fuse.RemoveRequest) error } // Rename implements NodeRenamer -func (dir *Directory) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error { - cur, err := dir.dir.Child(req.OldName) +func (d *Directory) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error { + cur, err := d.dir.Child(req.OldName) if err != nil { return err } - err = dir.dir.Unlink(req.OldName) + err = d.dir.Unlink(req.OldName) if err != nil { return err } diff --git a/fuse/ipns/mount_unix.go b/fuse/ipns/mount_unix.go index c04cc45a4..34a8eef51 100644 --- a/fuse/ipns/mount_unix.go +++ b/fuse/ipns/mount_unix.go @@ -12,7 +12,7 @@ import ( // Mount mounts ipns at a given location, and returns a mount.Mount instance. func Mount(ipfs *core.IpfsNode, ipnsmp, ipfsmp string) (mount.Mount, error) { - coreApi, err := coreapi.NewCoreAPI(ipfs) + coreAPI, err := coreapi.NewCoreAPI(ipfs) if err != nil { return nil, err } @@ -22,12 +22,12 @@ func Mount(ipfs *core.IpfsNode, ipnsmp, ipfsmp string) (mount.Mount, error) { return nil, err } - allow_other := cfg.Mounts.FuseAllowOther + allowOther := cfg.Mounts.FuseAllowOther - fsys, err := NewFileSystem(ipfs.Context(), coreApi, ipfsmp, ipnsmp) + fsys, err := NewFileSystem(ipfs.Context(), coreAPI, ipfsmp, ipnsmp) if err != nil { return nil, err } - return mount.NewMount(ipfs.Process, fsys, ipnsmp, allow_other) + return mount.NewMount(ipfs.Process, fsys, ipnsmp, allowOther) } diff --git a/fuse/mount/fuse.go b/fuse/mount/fuse.go index 99f374043..b1060e6fd 100644 --- a/fuse/mount/fuse.go +++ b/fuse/mount/fuse.go @@ -30,7 +30,7 @@ type mount struct { // Mount mounts a fuse fs.FS at a given location, and returns a Mount instance. // parent is a ContextGroup to bind the mount's ContextGroup to. -func NewMount(p goprocess.Process, fsys fs.FS, mountpoint string, allow_other bool) (Mount, error) { +func NewMount(p goprocess.Process, fsys fs.FS, mountpoint string, allowOther bool) (Mount, error) { var conn *fuse.Conn var err error @@ -39,7 +39,7 @@ func NewMount(p goprocess.Process, fsys fs.FS, mountpoint string, allow_other bo fuse.AsyncRead(), } - if allow_other { + if allowOther { mountOpts = append(mountOpts, fuse.AllowOther()) } conn, err = fuse.Mount(mountpoint, mountOpts...) diff --git a/fuse/readonly/mount_unix.go b/fuse/readonly/mount_unix.go index 87e4b33a7..19be37abe 100644 --- a/fuse/readonly/mount_unix.go +++ b/fuse/readonly/mount_unix.go @@ -15,7 +15,7 @@ func Mount(ipfs *core.IpfsNode, mountpoint string) (mount.Mount, error) { if err != nil { return nil, err } - allow_other := cfg.Mounts.FuseAllowOther + allowOther := cfg.Mounts.FuseAllowOther fsys := NewFileSystem(ipfs) - return mount.NewMount(ipfs.Process, fsys, mountpoint, allow_other) + return mount.NewMount(ipfs.Process, fsys, mountpoint, allowOther) } diff --git a/fuse/readonly/readonly_unix.go b/fuse/readonly/readonly_unix.go index a4d6f2513..39ca972e5 100644 --- a/fuse/readonly/readonly_unix.go +++ b/fuse/readonly/readonly_unix.go @@ -180,11 +180,11 @@ func (s *Node) Lookup(ctx context.Context, name string) (fs.Node, error) { case os.ErrNotExist, mdag.ErrLinkNotFound: // todo: make this error more versatile. return nil, fuse.ENOENT + case nil: + // noop default: log.Errorf("fuse lookup %q: %s", name, err) return nil, fuse.EIO - case nil: - // noop } nd, err := s.Ipfs.DAG.Get(ctx, link.Cid) diff --git a/gc/gc.go b/gc/gc.go index e3b0fda68..851b42d3b 100644 --- a/gc/gc.go +++ b/gc/gc.go @@ -167,7 +167,7 @@ func Descendants(ctx context.Context, getLinks dag.GetLinks, set *cid.Set, roots verboseCidError := func(err error) error { if strings.Contains(err.Error(), verifcid.ErrBelowMinimumHashLength.Error()) || strings.Contains(err.Error(), verifcid.ErrPossiblyInsecureHashFunction.Error()) { - err = fmt.Errorf("\"%s\"\nPlease run 'ipfs pin verify'"+ + err = fmt.Errorf("\"%s\"\nPlease run 'ipfs pin verify'"+ //nolint " to list insecure hashes. If you want to read them,"+ " please downgrade your go-ipfs to 0.4.13\n", err) log.Error(err) diff --git a/go.mod b/go.mod index 3ee91cfd2..18f145e11 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/ceramicnetwork/go-dag-jose v0.1.0 github.com/cespare/xxhash v1.1.0 github.com/cheggaaa/pb v1.0.29 - github.com/coreos/go-systemd/v22 v22.3.2 + github.com/coreos/go-systemd/v22 v22.4.0 github.com/dustin/go-humanize v1.0.0 github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302 github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 @@ -18,9 +18,9 @@ require ( github.com/ipfs/go-bitswap v0.10.2 github.com/ipfs/go-block-format v0.0.3 github.com/ipfs/go-blockservice v0.4.0 - github.com/ipfs/go-cid v0.3.0 + github.com/ipfs/go-cid v0.3.2 github.com/ipfs/go-cidutil v0.1.0 - github.com/ipfs/go-datastore v0.5.1 + github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-detect-race v0.0.1 github.com/ipfs/go-ds-badger v0.3.0 github.com/ipfs/go-ds-flatfs v0.5.1 @@ -46,7 +46,7 @@ require ( github.com/ipfs/go-ipld-format v0.4.0 github.com/ipfs/go-ipld-git v0.1.1 github.com/ipfs/go-ipld-legacy v0.1.1 - github.com/ipfs/go-ipns v0.2.0 + github.com/ipfs/go-ipns v0.3.0 github.com/ipfs/go-log v1.0.5 github.com/ipfs/go-merkledag v0.6.0 github.com/ipfs/go-metrics-interface v0.0.1 @@ -63,12 +63,12 @@ require ( github.com/ipld/go-car v0.4.0 github.com/ipld/go-car/v2 v2.4.0 github.com/ipld/go-codec-dagpb v1.4.1 - github.com/ipld/go-ipld-prime v0.17.0 + github.com/ipld/go-ipld-prime v0.18.0 github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c github.com/jbenet/go-temp-err-catcher v0.1.0 github.com/jbenet/goprocess v0.1.4 github.com/libp2p/go-doh-resolver v0.4.0 - github.com/libp2p/go-libp2p v0.22.0 + github.com/libp2p/go-libp2p v0.23.2 github.com/libp2p/go-libp2p-core v0.20.1 // indirect github.com/libp2p/go-libp2p-http v0.2.1 github.com/libp2p/go-libp2p-kad-dht v0.18.0 @@ -77,19 +77,19 @@ require ( github.com/libp2p/go-libp2p-pubsub v0.6.1 github.com/libp2p/go-libp2p-pubsub-router v0.5.0 github.com/libp2p/go-libp2p-record v0.2.0 - github.com/libp2p/go-libp2p-routing-helpers v0.2.3 + github.com/libp2p/go-libp2p-routing-helpers v0.4.0 github.com/libp2p/go-libp2p-testing v0.12.0 github.com/libp2p/go-socket-activation v0.1.0 github.com/miekg/dns v1.1.50 github.com/mitchellh/go-homedir v1.1.0 - github.com/multiformats/go-multiaddr v0.6.0 + github.com/multiformats/go-multiaddr v0.7.0 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multibase v0.1.1 - github.com/multiformats/go-multicodec v0.5.0 + github.com/multiformats/go-multicodec v0.6.0 github.com/multiformats/go-multihash v0.2.1 github.com/opentracing/opentracing-go v1.2.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.12.1 + github.com/prometheus/client_golang v1.13.0 github.com/prometheus/common v0.37.0 // indirect github.com/stretchr/testify v1.8.0 github.com/syndtr/goleveldb v1.0.0 @@ -108,15 +108,16 @@ require ( go.opentelemetry.io/otel/trace v1.7.0 go.uber.org/dig v1.14.1 go.uber.org/fx v1.17.1 - go.uber.org/zap v1.22.0 + go.uber.org/zap v1.23.0 golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab + golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 ) require ( github.com/benbjohnson/clock v1.3.0 - github.com/ipfs/go-delegated-routing v0.3.0 + github.com/ipfs/go-delegated-routing v0.6.0 + github.com/ipfs/go-ipfs-redirects-file v0.1.1 github.com/ipfs/go-log/v2 v2.5.1 ) @@ -129,7 +130,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cheekybits/genny v1.0.0 // indirect github.com/containerd/cgroups v1.0.4 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect github.com/cskr/pubsub v1.0.2 // indirect @@ -138,7 +138,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/dgraph-io/badger v1.6.2 // indirect github.com/dgraph-io/ristretto v0.0.2 // indirect - github.com/docker/go-units v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/flynn/noise v1.0.0 // indirect @@ -151,6 +151,7 @@ require ( github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect @@ -167,10 +168,10 @@ require ( github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect github.com/ipfs/go-ipfs-pq v0.0.2 // indirect github.com/ipfs/go-peertaskqueue v0.7.1 // indirect - github.com/ipld/edelweiss v0.1.4 // indirect + github.com/ipld/edelweiss v0.2.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/klauspost/compress v1.15.1 // indirect - github.com/klauspost/cpuid/v2 v2.1.0 // indirect + github.com/klauspost/compress v1.15.10 // indirect + github.com/klauspost/cpuid/v2 v2.1.1 // indirect github.com/koron/go-ssdp v0.0.3 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect @@ -186,14 +187,14 @@ require ( github.com/libp2p/go-netroute v0.2.0 // indirect github.com/libp2p/go-openssl v0.1.0 // indirect github.com/libp2p/go-reuseport v0.2.0 // indirect - github.com/libp2p/go-yamux/v3 v3.1.2 // indirect + github.com/libp2p/go-yamux/v4 v4.0.0 // indirect github.com/libp2p/zeroconf/v2 v2.2.0 // indirect - github.com/lucas-clemente/quic-go v0.28.1 // indirect - github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect - github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect + github.com/lucas-clemente/quic-go v0.29.1 // indirect + github.com/marten-seemann/qpack v0.2.1 // indirect github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect + github.com/marten-seemann/webtransport-go v0.1.1 // indirect github.com/mattn/go-colorable v0.1.4 // indirect github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-pointer v0.0.1 // indirect @@ -204,7 +205,7 @@ require ( github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect - github.com/multiformats/go-base32 v0.0.4 // indirect + github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multistream v0.3.3 // indirect @@ -227,6 +228,7 @@ require ( github.com/tidwall/gjson v1.14.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect @@ -239,9 +241,9 @@ require ( go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect - golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 // indirect + golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect + golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect diff --git a/go.sum b/go.sum index 4845795bc..dd9220fc7 100644 --- a/go.sum +++ b/go.sum @@ -130,7 +130,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo= github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30= @@ -163,8 +162,8 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU= +github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -198,8 +197,9 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -472,8 +472,8 @@ github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67Fexh github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o= -github.com/ipfs/go-cid v0.3.0 h1:gT6Cbs6YePaBNc7l6v5EXt0xTMup1jGV5EU1N+QLVpY= -github.com/ipfs/go-cid v0.3.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= +github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc= +github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw= github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s= github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q= github.com/ipfs/go-cidutil v0.1.0/go.mod h1:e7OEVBMIv9JaOxt9zaGEmAoSlXW9jdFZ5lP/0PwcfpA= @@ -487,10 +487,10 @@ github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13X github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= -github.com/ipfs/go-datastore v0.5.1 h1:WkRhLuISI+XPD0uk3OskB0fYFSyqK8Ob5ZYew9Qa1nQ= -github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= -github.com/ipfs/go-delegated-routing v0.3.0 h1:pF5apOJ/xdQkj22mRahW9GmSuCkgMLparKZWKJBO4CE= -github.com/ipfs/go-delegated-routing v0.3.0/go.mod h1:2w79E1/G9YOaxyJJQgqIFSQaa/GdS2zSATEpK8aJUBM= +github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= +github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= +github.com/ipfs/go-delegated-routing v0.6.0 h1:+M1siyTB2H4mHzEnbWjepQxlmKbapVWdbYLexSDODpg= +github.com/ipfs/go-delegated-routing v0.6.0/go.mod h1:FJjhCChfcWK9z6OXo2jwKKJoxq1JlEWG7YTvwaA7UbI= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= @@ -565,6 +565,8 @@ github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= github.com/ipfs/go-ipfs-provider v0.7.1 h1:eKToBUAb6ZY8iiA6AYVxzW4G1ep67XUaaEBUIYpxhfw= github.com/ipfs/go-ipfs-provider v0.7.1/go.mod h1:QwdDYRYnC5sYGLlOwVDY/0ZB6T3zcMtu+5+GdGeUuw8= +github.com/ipfs/go-ipfs-redirects-file v0.1.1 h1:Io++k0Vf/wK+tfnhEh63Yte1oQK5VGT2hIEYpD0Rzx8= +github.com/ipfs/go-ipfs-redirects-file v0.1.1/go.mod h1:tAwRjCV0RjLTjH8DR/AU7VYvfQECg+lpUy2Mdzv7gyk= github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY= @@ -589,8 +591,8 @@ github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2cdcc= github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.1.2/go.mod h1:ioQ0j02o6jdIVW+bmi18f4k2gRf0AV3kZ9KeHYHICnQ= -github.com/ipfs/go-ipns v0.2.0 h1:BgmNtQhqOw5XEZ8RAfWEpK4DhqaYiuP6h71MhIp7xXU= -github.com/ipfs/go-ipns v0.2.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= +github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A= +github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= @@ -649,8 +651,8 @@ github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPm github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY= github.com/ipfs/tar-utils v0.0.2 h1:UNgHB4x/PPzbMkmJi+7EqC9LNMPDztOVSnx1HAqSNg4= github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM= -github.com/ipld/edelweiss v0.1.4 h1:g4+C2Ph+8SV2MCJBG3oRtetvxJYAS2WzlNGgsOY95iM= -github.com/ipld/edelweiss v0.1.4/go.mod h1:JX1MR06BPcTOF+5xCYDLnylYkXS15iUN0/RXVSiUIQs= +github.com/ipld/edelweiss v0.2.0 h1:KfAZBP8eeJtrLxLhi7r3N0cBCo7JmwSRhOJp3WSpNjk= +github.com/ipld/edelweiss v0.2.0/go.mod h1:FJAzJRCep4iI8FOFlRriN9n0b7OuX3T/S9++NpBDmA4= github.com/ipld/go-car v0.4.0 h1:U6W7F1aKF/OJMHovnOVdst2cpQE5GhmHibQkAixgNcQ= github.com/ipld/go-car v0.4.0/go.mod h1:Uslcn4O9cBKK9wqHm/cLTFacg6RAPv6LZx2mxd2Ypl4= github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI= @@ -666,8 +668,8 @@ github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHt github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM= github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA= -github.com/ipld/go-ipld-prime v0.17.0 h1:+U2peiA3aQsE7mrXjD2nYZaZrCcakoz2Wge8K42Ld8g= -github.com/ipld/go-ipld-prime v0.17.0/go.mod h1:aYcKm5TIvGfY8P3QBKz/2gKcLxzJ1zDaD+o0bOowhgs= +github.com/ipld/go-ipld-prime v0.18.0 h1:xUk7NUBSWHEXdjiOu2sLXouFJOMs0yoYzeI5RAqhYQo= +github.com/ipld/go-ipld-prime v0.18.0/go.mod h1:735yXW548CKrLwVCYXzqx90p5deRJMVVxM9eJ4Qe+qE= github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73 h1:TsyATB2ZRRQGTwafJdgEUQkmjOExRV0DNokcihZxbnQ= github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= @@ -720,13 +722,13 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= -github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= +github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0= -github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0= +github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -783,8 +785,8 @@ github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2 github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= github.com/libp2p/go-libp2p v0.18.0/go.mod h1:+veaZ9z1SZQhmc5PW78jvnnxZ89Mgvmh4cggO11ETmw= -github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw= -github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4= +github.com/libp2p/go-libp2p v0.23.2 h1:yqyTeKQJyofWXxEv/eEVUvOrGdt/9x+0PIQ4N1kaxmE= +github.com/libp2p/go-libp2p v0.23.2/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= @@ -936,8 +938,9 @@ github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3qu github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y= github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= -github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY= github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= +github.com/libp2p/go-libp2p-routing-helpers v0.4.0 h1:b7y4aixQ7AwbqYfcOQ6wTw8DQvuRZeTAA0Od3YYN5yc= +github.com/libp2p/go-libp2p-routing-helpers v0.4.0/go.mod h1:dYEAgkVhqho3/YKxfOEGdFMIcWfAFNlZX8iAIihYA2E= github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0= github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= @@ -1104,8 +1107,8 @@ github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZj github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs= github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= -github.com/libp2p/go-yamux/v3 v3.1.2 h1:lNEy28MBk1HavUAlzKgShp+F6mn/ea1nDYWftZhFW9Q= -github.com/libp2p/go-yamux/v3 v3.1.2/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= +github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= +github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= @@ -1116,33 +1119,31 @@ github.com/lucas-clemente/quic-go v0.21.2/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0 github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= -github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU= -github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0= +github.com/lucas-clemente/quic-go v0.29.1 h1:Z+WMJ++qMLhvpFkRZA+jl3BTxUjm415YBmWanXB8zP0= +github.com/lucas-clemente/quic-go v0.29.1/go.mod h1:CTcNfLYJS2UuRNB+zcNlgvkjBhxX6Hm3WUxxAQx2mgE= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs= github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-15 v0.1.5/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= -github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= -github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= -github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ= -github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM= github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU= github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= +github.com/marten-seemann/webtransport-go v0.1.1 h1:TnyKp3pEXcDooTaNn4s9dYpMJ7kMnTp7k5h+SgYP/mc= +github.com/marten-seemann/webtransport-go v0.1.1/go.mod h1:kBEh5+RSvOA4troP1vyOVBWK4MIMzDICXVrvCPrYcrM= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -1210,8 +1211,8 @@ github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= -github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= @@ -1228,8 +1229,8 @@ github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9x github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc= github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug= -github.com/multiformats/go-multiaddr v0.6.0 h1:qMnoOPj2s8xxPU5kZ57Cqdr0hHhARz7mFsPMIiYNqzg= -github.com/multiformats/go-multiaddr v0.6.0/go.mod h1:F4IpaKZuPP360tOMn2Tpyu0At8w23aRyVqeK0DbFeGM= +github.com/multiformats/go-multiaddr v0.7.0 h1:gskHcdaCyPtp9XskVwtvEeQOG465sCohbQIirSyqxrc= +github.com/multiformats/go-multiaddr v0.7.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= @@ -1255,8 +1256,8 @@ github.com/multiformats/go-multicodec v0.2.0/go.mod h1:/y4YVwkfMyry5kFbMTbLJKErh github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multicodec v0.3.1-0.20211210143421-a526f306ed2c/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= -github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs= -github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues= +github.com/multiformats/go-multicodec v0.6.0 h1:KhH2kSuCARyuJraYMFxrNO3DqIaYhOdS039kbhgVwpE= +github.com/multiformats/go-multicodec v0.6.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= @@ -1370,8 +1371,9 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1512,9 +1514,12 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= +github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb h1:Ywfo8sUltxogBpFuMOFRrrSifO788kAFxmvVw31PtQQ= +github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -1651,8 +1656,8 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0= -go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= @@ -1705,8 +1710,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 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-20210615023648-acb5c1269671/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 h1:rxKZ2gOnYxjfmakvUUqh9Gyb6KXfrj7JWTxORTYqb0E= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b h1:SCE/18RnFsLrjydh/R/s5EVvHoZprqEQUuoxK8q2Pc4= +golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= 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= @@ -1793,8 +1798,8 @@ golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= -golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 h1:KafLifaRFIuSJ5C+7CyFJOF9haxKNC1CEIDk8GX6X0k= +golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 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= @@ -1909,8 +1914,9 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/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 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index f3e9841e8..219f136f7 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -35,7 +35,7 @@ const LockFile = "repo.lock" var log = logging.Logger("fsrepo") -// version number that we are currently expecting to see +// RepoVersion is the version number that we are currently expecting to see var RepoVersion = 12 var migrationInstructions = `See https://github.com/ipfs/fs-repo-migrations/blob/master/run.md @@ -383,7 +383,7 @@ func (r *FSRepo) SetAPIAddr(addr ma.Multiaddr) error { } // Remove the temp file when rename return error if err1 := os.Remove(filepath.Join(r.path, "."+apiFile+".tmp")); err1 != nil { - return fmt.Errorf("File Rename error: %s, File remove error: %s", err.Error(), + return fmt.Errorf("file Rename error: %s, file remove error: %s", err.Error(), err1.Error()) } return err @@ -422,7 +422,7 @@ func (r *FSRepo) SetGatewayAddr(addr net.Addr) error { } // Remove the temp file when rename return error if err1 := os.Remove(tmpPath); err1 != nil { - return fmt.Errorf("File Rename error: %w, File remove error: %s", err, err1.Error()) + return fmt.Errorf("file Rename error: %w, file remove error: %s", err, err1.Error()) } return err } diff --git a/repo/fsrepo/migrations/httpfetcher.go b/repo/fsrepo/migrations/httpfetcher.go index 9be7f9f0a..81e0e406d 100644 --- a/repo/fsrepo/migrations/httpfetcher.go +++ b/repo/fsrepo/migrations/httpfetcher.go @@ -16,7 +16,7 @@ const ( ) // HttpFetcher fetches files over HTTP -type HttpFetcher struct { +type HttpFetcher struct { //nolint distPath string gateway string limit int64 @@ -30,7 +30,7 @@ var _ Fetcher = (*HttpFetcher)(nil) // Specifying "" for distPath sets the default IPNS path. // Specifying "" for gateway sets the default. // Specifying 0 for fetchLimit sets the default, -1 means no limit. -func NewHttpFetcher(distPath, gateway, userAgent string, fetchLimit int64) *HttpFetcher { +func NewHttpFetcher(distPath, gateway, userAgent string, fetchLimit int64) *HttpFetcher { //nolint f := &HttpFetcher{ distPath: LatestIpfsDist, gateway: defaultGatewayURL, diff --git a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go index ba64b96df..ce7b490ef 100644 --- a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go +++ b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go @@ -28,7 +28,7 @@ const ( // Default maximum download size defaultFetchLimit = 1024 * 1024 * 512 - tempNodeTcpAddr = "/ip4/127.0.0.1/tcp/0" + tempNodeTCPAddr = "/ip4/127.0.0.1/tcp/0" ) type IpfsFetcher struct { @@ -188,12 +188,12 @@ func initTempNode(ctx context.Context, bootstrap []string, peers []peer.AddrInfo } // configure the temporary node - cfg.Routing.Type = config.NewOptionalString("dhtclient") + cfg.Routing.Type = "dhtclient" // Disable listening for inbound connections cfg.Addresses.Gateway = []string{} cfg.Addresses.API = []string{} - cfg.Addresses.Swarm = []string{tempNodeTcpAddr} + cfg.Addresses.Swarm = []string{tempNodeTCPAddr} if len(bootstrap) != 0 { cfg.Bootstrap = bootstrap diff --git a/repo/fsrepo/migrations/migrations.go b/repo/fsrepo/migrations/migrations.go index 9c556fe97..7e764b731 100644 --- a/repo/fsrepo/migrations/migrations.go +++ b/repo/fsrepo/migrations/migrations.go @@ -166,6 +166,8 @@ func GetMigrationFetcher(downloadSources []string, distPath string, newIpfsFetch if newIpfsFetcher != nil { fetchers = append(fetchers, newIpfsFetcher(distPath)) } + case "": + // Ignore empty string default: u, err := url.Parse(src) if err != nil { @@ -179,8 +181,6 @@ func GetMigrationFetcher(downloadSources []string, distPath string, newIpfsFetch return nil, errors.New("bad gateway address: url scheme must be http or https") } fetchers = append(fetchers, &RetryFetcher{NewHttpFetcher(distPath, u.String(), httpUserAgent, 0), numTriesPerHTTP}) - case "": - // Ignore empty string } } diff --git a/repo/repo.go b/repo/repo.go index 3c6103177..bec02049d 100644 --- a/repo/repo.go +++ b/repo/repo.go @@ -15,7 +15,7 @@ import ( ) var ( - ErrApiNotRunning = errors.New("api not running") + ErrApiNotRunning = errors.New("api not running") //nolint ) // Repo represents all persistent data of a given ipfs node. diff --git a/routing/composer.go b/routing/composer.go new file mode 100644 index 000000000..ed3f2d13e --- /dev/null +++ b/routing/composer.go @@ -0,0 +1,74 @@ +package routing + +import ( + "context" + + "github.com/hashicorp/go-multierror" + "github.com/ipfs/go-cid" + routinghelpers "github.com/libp2p/go-libp2p-routing-helpers" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/routing" + "github.com/multiformats/go-multihash" +) + +var _ routinghelpers.ProvideManyRouter = &Composer{} +var _ routing.Routing = &Composer{} + +type Composer struct { + GetValueRouter routing.Routing + PutValueRouter routing.Routing + FindPeersRouter routing.Routing + FindProvidersRouter routing.Routing + ProvideRouter routing.Routing +} + +func (c *Composer) Provide(ctx context.Context, cid cid.Cid, provide bool) error { + return c.ProvideRouter.Provide(ctx, cid, provide) +} + +func (c *Composer) ProvideMany(ctx context.Context, keys []multihash.Multihash) error { + pmr, ok := c.ProvideRouter.(routinghelpers.ProvideManyRouter) + if !ok { + return nil + } + + return pmr.ProvideMany(ctx, keys) +} + +func (c *Composer) Ready() bool { + pmr, ok := c.ProvideRouter.(routinghelpers.ProvideManyRouter) + if !ok { + return false + } + + return pmr.Ready() +} + +func (c *Composer) FindProvidersAsync(ctx context.Context, cid cid.Cid, count int) <-chan peer.AddrInfo { + return c.FindProvidersRouter.FindProvidersAsync(ctx, cid, count) +} + +func (c *Composer) FindPeer(ctx context.Context, pid peer.ID) (peer.AddrInfo, error) { + return c.FindPeersRouter.FindPeer(ctx, pid) +} + +func (c *Composer) PutValue(ctx context.Context, key string, val []byte, opts ...routing.Option) error { + return c.PutValueRouter.PutValue(ctx, key, val, opts...) +} + +func (c *Composer) GetValue(ctx context.Context, key string, opts ...routing.Option) ([]byte, error) { + return c.GetValueRouter.GetValue(ctx, key, opts...) +} + +func (c *Composer) SearchValue(ctx context.Context, key string, opts ...routing.Option) (<-chan []byte, error) { + return c.GetValueRouter.SearchValue(ctx, key, opts...) +} + +func (c *Composer) Bootstrap(ctx context.Context) error { + errfp := c.FindPeersRouter.Bootstrap(ctx) + errfps := c.FindProvidersRouter.Bootstrap(ctx) + errgv := c.GetValueRouter.Bootstrap(ctx) + errpv := c.PutValueRouter.Bootstrap(ctx) + errp := c.ProvideRouter.Bootstrap(ctx) + return multierror.Append(errfp, errfps, errgv, errpv, errp) +} diff --git a/routing/delegated.go b/routing/delegated.go index 030fae8a3..d8e818bc3 100644 --- a/routing/delegated.go +++ b/routing/delegated.go @@ -1,93 +1,315 @@ package routing import ( - "strconv" + "context" + "encoding/base64" + "errors" + "fmt" + "net/http" + "github.com/ipfs/go-datastore" drc "github.com/ipfs/go-delegated-routing/client" drp "github.com/ipfs/go-delegated-routing/gen/proto" + logging "github.com/ipfs/go-log" "github.com/ipfs/kubo/config" + dht "github.com/libp2p/go-libp2p-kad-dht" + "github.com/libp2p/go-libp2p-kad-dht/dual" + "github.com/libp2p/go-libp2p-kad-dht/fullrt" + record "github.com/libp2p/go-libp2p-record" routinghelpers "github.com/libp2p/go-libp2p-routing-helpers" + ic "github.com/libp2p/go-libp2p/core/crypto" + host "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/routing" + ma "github.com/multiformats/go-multiaddr" + "github.com/multiformats/go-multicodec" ) -type TieredRouter interface { - routing.Routing - ProvideMany() ProvideMany -} +var log = logging.Logger("routing/delegated") -var _ TieredRouter = &Tiered{} +func Parse(routers config.Routers, methods config.Methods, extraDHT *ExtraDHTParams, extraReframe *ExtraReframeParams) (routing.Routing, error) { + if err := methods.Check(); err != nil { + return nil, err + } -// Tiered is a routing Tiered implementation providing some extra methods to fill -// some special use cases when initializing the client. -type Tiered struct { - routinghelpers.Tiered -} + createdRouters := make(map[string]routing.Routing) + finalRouter := &Composer{} -// ProvideMany returns a ProvideMany implementation including all Routers that -// implements ProvideMany -func (ds Tiered) ProvideMany() ProvideMany { - var pms []ProvideMany - for _, r := range ds.Tiered.Routers { - pm, ok := r.(ProvideMany) - if !ok { - continue + // Create all needed routers from method names + for mn, m := range methods { + router, err := parse(make(map[string]bool), createdRouters, m.RouterName, routers, extraDHT, extraReframe) + if err != nil { + return nil, err } - pms = append(pms, pm) + + switch mn { + case config.MethodNamePutIPNS: + finalRouter.PutValueRouter = router + case config.MethodNameGetIPNS: + finalRouter.GetValueRouter = router + case config.MethodNameFindPeers: + finalRouter.FindPeersRouter = router + case config.MethodNameFindProviders: + finalRouter.FindProvidersRouter = router + case config.MethodNameProvide: + finalRouter.ProvideRouter = router + } + + log.Info("using method ", mn, " with router ", m.RouterName) } - if len(pms) == 0 { - return nil - } - - return &ProvideManyWrapper{pms: pms} + return finalRouter, nil } -const defaultPriority = 100000 - -// GetPriority extract priority from config params. -// Small numbers represent more important routers. -func GetPriority(params map[string]string) int { - param := params[string(config.RouterParamPriority)] - if param == "" { - return defaultPriority +func parse(visited map[string]bool, + createdRouters map[string]routing.Routing, + routerName string, + routersCfg config.Routers, + extraDHT *ExtraDHTParams, + extraReframe *ExtraReframeParams, +) (routing.Routing, error) { + // check if we already created it + r, ok := createdRouters[routerName] + if ok { + return r, nil } - p, err := strconv.Atoi(param) - if err != nil { - return defaultPriority + // check if we are in a dep loop + if visited[routerName] { + return nil, fmt.Errorf("dependency loop creating router with name %q", routerName) } - return p -} + // set node as visited + visited[routerName] = true -// RoutingFromConfig creates a Routing instance from the specified configuration. -func RoutingFromConfig(c config.Router) (routing.Routing, error) { - switch { - case c.Type == string(config.RouterTypeReframe): - return reframeRoutingFromConfig(c) - default: - return nil, &RouterTypeNotFoundError{c.Type} - } -} - -func reframeRoutingFromConfig(conf config.Router) (routing.Routing, error) { - var dr drp.DelegatedRouting_Client - - param := string(config.RouterParamEndpoint) - addr, ok := conf.Parameters[param] + cfg, ok := routersCfg[routerName] if !ok { - return nil, NewParamNeededErr(param, conf.Type) + return nil, fmt.Errorf("config for router with name %q not found", routerName) + } + + var router routing.Routing + var err error + switch cfg.Type { + case config.RouterTypeReframe: + router, err = reframeRoutingFromConfig(cfg.Router, extraReframe) + case config.RouterTypeDHT: + router, err = dhtRoutingFromConfig(cfg.Router, extraDHT) + case config.RouterTypeParallel: + crp := cfg.Parameters.(*config.ComposableRouterParams) + var pr []*routinghelpers.ParallelRouter + for _, cr := range crp.Routers { + ri, err := parse(visited, createdRouters, cr.RouterName, routersCfg, extraDHT, extraReframe) + if err != nil { + return nil, err + } + + pr = append(pr, &routinghelpers.ParallelRouter{ + Router: ri, + IgnoreError: cr.IgnoreErrors, + Timeout: cr.Timeout.Duration, + ExecuteAfter: cr.ExecuteAfter.WithDefault(0), + }) + + } + + router = routinghelpers.NewComposableParallel(pr) + case config.RouterTypeSequential: + crp := cfg.Parameters.(*config.ComposableRouterParams) + var sr []*routinghelpers.SequentialRouter + for _, cr := range crp.Routers { + ri, err := parse(visited, createdRouters, cr.RouterName, routersCfg, extraDHT, extraReframe) + if err != nil { + return nil, err + } + + sr = append(sr, &routinghelpers.SequentialRouter{ + Router: ri, + IgnoreError: cr.IgnoreErrors, + Timeout: cr.Timeout.Duration, + }) + + } + + router = routinghelpers.NewComposableSequential(sr) + default: + return nil, fmt.Errorf("unknown router type %q", cfg.Type) } - dr, err := drp.New_DelegatedRouting_Client(addr) if err != nil { return nil, err } - c := drc.NewClient(dr) + createdRouters[routerName] = router + + log.Info("created router ", routerName, " with params ", cfg.Parameters) + + return router, nil +} + +type ExtraReframeParams struct { + PeerID string + Addrs []string + PrivKeyB64 string +} + +func reframeRoutingFromConfig(conf config.Router, extraReframe *ExtraReframeParams) (routing.Routing, error) { + var dr drp.DelegatedRouting_Client + + params := conf.Parameters.(*config.ReframeRouterParams) + + if params.Endpoint == "" { + return nil, NewParamNeededErr("Endpoint", conf.Type) + } + + // Increase per-host connection pool since we are making lots of concurrent requests. + transport := http.DefaultTransport.(*http.Transport).Clone() + transport.MaxIdleConns = 500 + transport.MaxIdleConnsPerHost = 100 + + delegateHTTPClient := &http.Client{ + Transport: transport, + } + dr, err := drp.New_DelegatedRouting_Client(params.Endpoint, + drp.DelegatedRouting_Client_WithHTTPClient(delegateHTTPClient), + ) + if err != nil { + return nil, err + } + + var c *drc.Client + + // this path is for tests only + if extraReframe == nil { + c, err = drc.NewClient(dr, nil, nil) + if err != nil { + return nil, err + } + } else { + prov, err := createProvider(extraReframe.PeerID, extraReframe.Addrs) + if err != nil { + return nil, err + } + + key, err := decodePrivKey(extraReframe.PrivKeyB64) + if err != nil { + return nil, err + } + + c, err = drc.NewClient(dr, prov, key) + if err != nil { + return nil, err + } + } + crc := drc.NewContentRoutingClient(c) return &reframeRoutingWrapper{ Client: c, ContentRoutingClient: crc, }, nil } + +func decodePrivKey(keyB64 string) (ic.PrivKey, error) { + pk, err := base64.StdEncoding.DecodeString(keyB64) + if err != nil { + return nil, err + } + + return ic.UnmarshalPrivateKey(pk) +} + +func createProvider(peerID string, addrs []string) (*drc.Provider, error) { + pID, err := peer.Decode(peerID) + if err != nil { + return nil, err + } + + var mas []ma.Multiaddr + for _, a := range addrs { + m, err := ma.NewMultiaddr(a) + if err != nil { + return nil, err + } + + mas = append(mas, m) + } + + return &drc.Provider{ + Peer: peer.AddrInfo{ + ID: pID, + Addrs: mas, + }, + ProviderProto: []drc.TransferProtocol{ + {Codec: multicodec.TransportBitswap}, + }, + }, nil +} + +type ExtraDHTParams struct { + BootstrapPeers []peer.AddrInfo + Host host.Host + Validator record.Validator + Datastore datastore.Batching + Context context.Context +} + +func dhtRoutingFromConfig(conf config.Router, extra *ExtraDHTParams) (routing.Routing, error) { + params, ok := conf.Parameters.(*config.DHTRouterParams) + if !ok { + return nil, errors.New("incorrect params for DHT router") + } + + if params.AcceleratedDHTClient { + return createFullRT(extra) + } + + var mode dht.ModeOpt + switch params.Mode { + case config.DHTModeAuto: + mode = dht.ModeAuto + case config.DHTModeClient: + mode = dht.ModeClient + case config.DHTModeServer: + mode = dht.ModeServer + default: + return nil, fmt.Errorf("invalid DHT mode: %q", params.Mode) + } + + return createDHT(extra, params.PublicIPNetwork, mode) +} + +func createDHT(params *ExtraDHTParams, public bool, mode dht.ModeOpt) (routing.Routing, error) { + var opts []dht.Option + + if public { + opts = append(opts, dht.QueryFilter(dht.PublicQueryFilter), + dht.RoutingTableFilter(dht.PublicRoutingTableFilter), + dht.RoutingTablePeerDiversityFilter(dht.NewRTPeerDiversityFilter(params.Host, 2, 3))) + } else { + opts = append(opts, dht.ProtocolExtension(dual.LanExtension), + dht.QueryFilter(dht.PrivateQueryFilter), + dht.RoutingTableFilter(dht.PrivateRoutingTableFilter)) + } + + opts = append(opts, + dht.Concurrency(10), + dht.Mode(mode), + dht.Datastore(params.Datastore), + dht.Validator(params.Validator), + dht.BootstrapPeers(params.BootstrapPeers...)) + + return dht.New( + params.Context, params.Host, opts..., + ) +} + +func createFullRT(params *ExtraDHTParams) (routing.Routing, error) { + return fullrt.NewFullRT(params.Host, + dht.DefaultPrefix, + fullrt.DHTOption( + dht.Validator(params.Validator), + dht.Datastore(params.Datastore), + dht.BootstrapPeers(params.BootstrapPeers...), + dht.BucketSize(20), + ), + ) +} diff --git a/routing/delegated_test.go b/routing/delegated_test.go index c1061f0eb..04b8e282f 100644 --- a/routing/delegated_test.go +++ b/routing/delegated_test.go @@ -1,121 +1,239 @@ package routing import ( - "context" + "encoding/base64" "testing" - "github.com/ipfs/go-cid" "github.com/ipfs/kubo/config" - routinghelpers "github.com/libp2p/go-libp2p-routing-helpers" - "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/core/routing" - "github.com/multiformats/go-multihash" + crypto "github.com/libp2p/go-libp2p/core/crypto" + peer "github.com/libp2p/go-libp2p/core/peer" "github.com/stretchr/testify/require" ) -func TestPriority(t *testing.T) { - require := require.New(t) - params := make(map[string]string) - p := GetPriority(params) - - require.Equal(defaultPriority, p) - - params[string(config.RouterParamPriority)] = "101" - - p = GetPriority(params) - - require.Equal(101, p) - - params[string(config.RouterParamPriority)] = "NAN" - - p = GetPriority(params) - - require.Equal(defaultPriority, p) -} - -func TestRoutingFromConfig(t *testing.T) { +func TestReframeRoutingFromConfig(t *testing.T) { require := require.New(t) - r, err := RoutingFromConfig(config.Router{ - Type: "unknown", - }) - - require.Nil(r) - require.EqualError(err, "router type unknown is not supported") - - r, err = RoutingFromConfig(config.Router{ - Type: string(config.RouterTypeReframe), - Parameters: make(map[string]string), - }) + r, err := reframeRoutingFromConfig(config.Router{ + Type: config.RouterTypeReframe, + Parameters: &config.ReframeRouterParams{}, + }, nil) require.Nil(r) require.EqualError(err, "configuration param 'Endpoint' is needed for reframe delegated routing types") - r, err = RoutingFromConfig(config.Router{ - Type: string(config.RouterTypeReframe), - Parameters: map[string]string{ - string(config.RouterParamEndpoint): "test", + r, err = reframeRoutingFromConfig(config.Router{ + Type: config.RouterTypeReframe, + Parameters: &config.ReframeRouterParams{ + Endpoint: "test", }, + }, nil) + + require.NoError(err) + require.NotNil(r) + + priv, pub, err := crypto.GenerateKeyPair(crypto.RSA, 2048) + require.NoError(err) + + id, err := peer.IDFromPublicKey(pub) + require.NoError(err) + + privM, err := crypto.MarshalPrivateKey(priv) + require.NoError(err) + + r, err = reframeRoutingFromConfig(config.Router{ + Type: config.RouterTypeReframe, + Parameters: &config.ReframeRouterParams{ + Endpoint: "test", + }, + }, &ExtraReframeParams{ + PeerID: id.String(), + Addrs: []string{"/ip4/0.0.0.0/tcp/4001"}, + PrivKeyB64: base64.StdEncoding.EncodeToString(privM), }) require.NotNil(r) require.NoError(err) } -func TestTieredRouter(t *testing.T) { +func TestParser(t *testing.T) { require := require.New(t) - tr := &Tiered{ - Tiered: routinghelpers.Tiered{ - Routers: []routing.Routing{routinghelpers.Null{}}, + router, err := Parse(config.Routers{ + "r1": config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeReframe, + Parameters: &config.ReframeRouterParams{ + Endpoint: "testEndpoint", + }, + }, }, - } + "r2": config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeSequential, + Parameters: &config.ComposableRouterParams{ + Routers: []config.ConfigRouter{ + { + RouterName: "r1", + }, + }, + }, + }, + }, + }, config.Methods{ + config.MethodNameFindPeers: config.Method{ + RouterName: "r1", + }, + config.MethodNameFindProviders: config.Method{ + RouterName: "r1", + }, + config.MethodNameGetIPNS: config.Method{ + RouterName: "r1", + }, + config.MethodNamePutIPNS: config.Method{ + RouterName: "r2", + }, + config.MethodNameProvide: config.Method{ + RouterName: "r2", + }, + }, &ExtraDHTParams{}, nil) - pm := tr.ProvideMany() - require.Nil(pm) + require.NoError(err) - tr.Tiered.Routers = append(tr.Tiered.Routers, &dummyRouter{}) + comp, ok := router.(*Composer) + require.True(ok) - pm = tr.ProvideMany() - require.NotNil(pm) + require.Equal(comp.FindPeersRouter, comp.FindProvidersRouter) + require.Equal(comp.ProvideRouter, comp.PutValueRouter) } -type dummyRouter struct { -} +func TestParserRecursive(t *testing.T) { + require := require.New(t) -func (dr *dummyRouter) Provide(context.Context, cid.Cid, bool) error { - panic("not implemented") + router, err := Parse(config.Routers{ + "reframe1": config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeReframe, + Parameters: &config.ReframeRouterParams{ + Endpoint: "testEndpoint1", + }, + }, + }, + "reframe2": config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeReframe, + Parameters: &config.ReframeRouterParams{ + Endpoint: "testEndpoint2", + }, + }, + }, + "reframe3": config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeReframe, + Parameters: &config.ReframeRouterParams{ + Endpoint: "testEndpoint3", + }, + }, + }, + "composable1": config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeSequential, + Parameters: &config.ComposableRouterParams{ + Routers: []config.ConfigRouter{ + { + RouterName: "reframe1", + }, + { + RouterName: "reframe2", + }, + }, + }, + }, + }, + "composable2": config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeParallel, + Parameters: &config.ComposableRouterParams{ + Routers: []config.ConfigRouter{ + { + RouterName: "composable1", + }, + { + RouterName: "reframe3", + }, + }, + }, + }, + }, + }, config.Methods{ + config.MethodNameFindPeers: config.Method{ + RouterName: "composable2", + }, + config.MethodNameFindProviders: config.Method{ + RouterName: "composable2", + }, + config.MethodNameGetIPNS: config.Method{ + RouterName: "composable2", + }, + config.MethodNamePutIPNS: config.Method{ + RouterName: "composable2", + }, + config.MethodNameProvide: config.Method{ + RouterName: "composable2", + }, + }, &ExtraDHTParams{}, nil) + + require.NoError(err) + + _, ok := router.(*Composer) + require.True(ok) } -func (dr *dummyRouter) FindProvidersAsync(context.Context, cid.Cid, int) <-chan peer.AddrInfo { - panic("not implemented") -} +func TestParserRecursiveLoop(t *testing.T) { + require := require.New(t) -func (dr *dummyRouter) FindPeer(context.Context, peer.ID) (peer.AddrInfo, error) { - panic("not implemented") -} + _, err := Parse(config.Routers{ + "composable1": config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeSequential, + Parameters: &config.ComposableRouterParams{ + Routers: []config.ConfigRouter{ + { + RouterName: "composable2", + }, + }, + }, + }, + }, + "composable2": config.RouterParser{ + Router: config.Router{ + Type: config.RouterTypeParallel, + Parameters: &config.ComposableRouterParams{ + Routers: []config.ConfigRouter{ + { + RouterName: "composable1", + }, + }, + }, + }, + }, + }, config.Methods{ + config.MethodNameFindPeers: config.Method{ + RouterName: "composable2", + }, + config.MethodNameFindProviders: config.Method{ + RouterName: "composable2", + }, + config.MethodNameGetIPNS: config.Method{ + RouterName: "composable2", + }, + config.MethodNamePutIPNS: config.Method{ + RouterName: "composable2", + }, + config.MethodNameProvide: config.Method{ + RouterName: "composable2", + }, + }, &ExtraDHTParams{}, nil) -func (dr *dummyRouter) PutValue(context.Context, string, []byte, ...routing.Option) error { - panic("not implemented") -} - -func (dr *dummyRouter) GetValue(context.Context, string, ...routing.Option) ([]byte, error) { - panic("not implemented") -} - -func (dr *dummyRouter) SearchValue(context.Context, string, ...routing.Option) (<-chan []byte, error) { - panic("not implemented") -} - -func (dr *dummyRouter) Bootstrap(context.Context) error { - panic("not implemented") -} - -func (dr *dummyRouter) ProvideMany(ctx context.Context, keys []multihash.Multihash) error { - panic("not implemented") -} - -func (dr *dummyRouter) Ready() bool { - panic("not implemented") + require.ErrorContains(err, "dependency loop creating router with name \"composable2\"") } diff --git a/routing/error.go b/routing/error.go index 15016a0e4..07186ab19 100644 --- a/routing/error.go +++ b/routing/error.go @@ -1,13 +1,17 @@ package routing -import "fmt" +import ( + "fmt" + + "github.com/ipfs/kubo/config" +) type ParamNeededError struct { ParamName string - RouterType string + RouterType config.RouterType } -func NewParamNeededErr(param, routing string) error { +func NewParamNeededErr(param string, routing config.RouterType) error { return &ParamNeededError{ ParamName: param, RouterType: routing, @@ -17,11 +21,3 @@ func NewParamNeededErr(param, routing string) error { func (e *ParamNeededError) Error() string { return fmt.Sprintf("configuration param '%v' is needed for %v delegated routing types", e.ParamName, e.RouterType) } - -type RouterTypeNotFoundError struct { - RouterType string -} - -func (e *RouterTypeNotFoundError) Error() string { - return fmt.Sprintf("router type %v is not supported", e.RouterType) -} diff --git a/routing/wrapper.go b/routing/wrapper.go index 95b7cffda..3a64d6a63 100644 --- a/routing/wrapper.go +++ b/routing/wrapper.go @@ -5,13 +5,13 @@ import ( "github.com/ipfs/go-cid" drc "github.com/ipfs/go-delegated-routing/client" + routinghelpers "github.com/libp2p/go-libp2p-routing-helpers" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/routing" - "github.com/multiformats/go-multihash" - "golang.org/x/sync/errgroup" ) var _ routing.Routing = &reframeRoutingWrapper{} +var _ routinghelpers.ProvideManyRouter = &reframeRoutingWrapper{} // reframeRoutingWrapper is a wrapper needed to construct the routing.Routing interface from // delegated-routing library. @@ -20,6 +20,10 @@ type reframeRoutingWrapper struct { *drc.ContentRoutingClient } +func (c *reframeRoutingWrapper) Provide(ctx context.Context, id cid.Cid, announce bool) error { + return c.ContentRoutingClient.Provide(ctx, id, announce) +} + func (c *reframeRoutingWrapper) FindProvidersAsync(ctx context.Context, cid cid.Cid, count int) <-chan peer.AddrInfo { return c.ContentRoutingClient.FindProvidersAsync(ctx, cid, count) } @@ -32,35 +36,7 @@ func (c *reframeRoutingWrapper) FindPeer(ctx context.Context, id peer.ID) (peer. return peer.AddrInfo{}, routing.ErrNotSupported } -type ProvideMany interface { - ProvideMany(ctx context.Context, keys []multihash.Multihash) error - Ready() bool -} - -var _ ProvideMany = &ProvideManyWrapper{} - -type ProvideManyWrapper struct { - pms []ProvideMany -} - -func (pmw *ProvideManyWrapper) ProvideMany(ctx context.Context, keys []multihash.Multihash) error { - var g errgroup.Group - for _, pm := range pmw.pms { - pm := pm - g.Go(func() error { - return pm.ProvideMany(ctx, keys) - }) - } - - return g.Wait() -} - -// Ready is ready if all providers are ready -func (pmw *ProvideManyWrapper) Ready() bool { - out := true - for _, pm := range pmw.pms { - out = out && pm.Ready() - } - - return out +type ProvideManyRouter interface { + routinghelpers.ProvideManyRouter + routing.Routing } diff --git a/routing/wrapper_test.go b/routing/wrapper_test.go deleted file mode 100644 index dd5f2f446..000000000 --- a/routing/wrapper_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package routing - -import ( - "context" - "errors" - "testing" - - "github.com/multiformats/go-multihash" -) - -func TestProvideManyWrapper_ProvideMany(t *testing.T) { - type fields struct { - pms []ProvideMany - } - tests := []struct { - name string - fields fields - wantErr bool - ready bool - }{ - { - name: "one provider", - fields: fields{ - pms: []ProvideMany{ - newDummyProvideMany(true, false), - }, - }, - wantErr: false, - ready: true, - }, - { - name: "two providers, no errors and ready", - fields: fields{ - pms: []ProvideMany{ - newDummyProvideMany(true, false), - newDummyProvideMany(true, false), - }, - }, - wantErr: false, - ready: true, - }, - { - name: "two providers, no ready, no error", - fields: fields{ - pms: []ProvideMany{ - newDummyProvideMany(true, false), - newDummyProvideMany(false, false), - }, - }, - wantErr: false, - ready: false, - }, - { - name: "two providers, no ready, and one erroing", - fields: fields{ - pms: []ProvideMany{ - newDummyProvideMany(true, false), - newDummyProvideMany(false, true), - }, - }, - wantErr: true, - ready: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - pmw := &ProvideManyWrapper{ - pms: tt.fields.pms, - } - if err := pmw.ProvideMany(context.Background(), nil); (err != nil) != tt.wantErr { - t.Errorf("ProvideManyWrapper.ProvideMany() error = %v, wantErr %v", err, tt.wantErr) - } - - if ready := pmw.Ready(); ready != tt.ready { - t.Errorf("ProvideManyWrapper.Ready() unexpected output = %v, want %v", ready, tt.ready) - } - }) - } -} - -func newDummyProvideMany(ready, failProviding bool) *dummyProvideMany { - return &dummyProvideMany{ - ready: ready, - failProviding: failProviding, - } -} - -type dummyProvideMany struct { - ready, failProviding bool -} - -func (dpm *dummyProvideMany) ProvideMany(ctx context.Context, keys []multihash.Multihash) error { - if dpm.failProviding { - return errors.New("error providing many") - } - - return nil -} -func (dpm *dummyProvideMany) Ready() bool { - return dpm.ready -} diff --git a/test/integration/addcat_test.go b/test/integration/addcat_test.go index 3564a20dd..45e8729ac 100644 --- a/test/integration/addcat_test.go +++ b/test/integration/addcat_test.go @@ -122,12 +122,12 @@ func DirectAddCat(data []byte, conf testutil.LatencyConfig) error { } defer catter.Close() - adderApi, err := coreapi.NewCoreAPI(adder) + adderAPI, err := coreapi.NewCoreAPI(adder) if err != nil { return err } - catterApi, err := coreapi.NewCoreAPI(catter) + catterAPI, err := coreapi.NewCoreAPI(catter) if err != nil { return err } @@ -147,12 +147,12 @@ func DirectAddCat(data []byte, conf testutil.LatencyConfig) error { return err } - added, err := adderApi.Unixfs().Add(ctx, files.NewBytesFile(data)) + added, err := adderAPI.Unixfs().Add(ctx, files.NewBytesFile(data)) if err != nil { return err } - readerCatted, err := catterApi.Unixfs().Get(ctx, added) + readerCatted, err := catterAPI.Unixfs().Get(ctx, added) if err != nil { return err } diff --git a/test/integration/bench_cat_test.go b/test/integration/bench_cat_test.go index 952f8e48b..d7e37dbb9 100644 --- a/test/integration/bench_cat_test.go +++ b/test/integration/bench_cat_test.go @@ -65,12 +65,12 @@ func benchCat(b *testing.B, data []byte, conf testutil.LatencyConfig) error { } defer catter.Close() - adderApi, err := coreapi.NewCoreAPI(adder) + adderAPI, err := coreapi.NewCoreAPI(adder) if err != nil { return err } - catterApi, err := coreapi.NewCoreAPI(catter) + catterAPI, err := coreapi.NewCoreAPI(catter) if err != nil { return err } @@ -90,13 +90,13 @@ func benchCat(b *testing.B, data []byte, conf testutil.LatencyConfig) error { return err } - added, err := adderApi.Unixfs().Add(ctx, files.NewBytesFile(data)) + added, err := adderAPI.Unixfs().Add(ctx, files.NewBytesFile(data)) if err != nil { return err } b.StartTimer() - readerCatted, err := catterApi.Unixfs().Get(ctx, added) + readerCatted, err := catterAPI.Unixfs().Get(ctx, added) if err != nil { return err } diff --git a/test/integration/three_legged_cat_test.go b/test/integration/three_legged_cat_test.go index f41c9a7dd..f0358272b 100644 --- a/test/integration/three_legged_cat_test.go +++ b/test/integration/three_legged_cat_test.go @@ -93,12 +93,12 @@ func RunThreeLeggedCat(data []byte, conf testutil.LatencyConfig) error { } defer catter.Close() - adderApi, err := coreapi.NewCoreAPI(adder) + adderAPI, err := coreapi.NewCoreAPI(adder) if err != nil { return err } - catterApi, err := coreapi.NewCoreAPI(catter) + catterAPI, err := coreapi.NewCoreAPI(catter) if err != nil { return err } @@ -117,12 +117,12 @@ func RunThreeLeggedCat(data []byte, conf testutil.LatencyConfig) error { return err } - added, err := adderApi.Unixfs().Add(ctx, files.NewBytesFile(data)) + added, err := adderAPI.Unixfs().Add(ctx, files.NewBytesFile(data)) if err != nil { return err } - readerCatted, err := catterApi.Unixfs().Get(ctx, added) + readerCatted, err := catterAPI.Unixfs().Get(ctx, added) if err != nil { return err } diff --git a/test/sharness/t0040-add-and-cat.sh b/test/sharness/t0040-add-and-cat.sh index 833d6043e..142ab8ec1 100755 --- a/test/sharness/t0040-add-and-cat.sh +++ b/test/sharness/t0040-add-and-cat.sh @@ -362,6 +362,113 @@ test_add_cat_file() { rm mountdir/same-file/hello.txt && rmdir mountdir/same-file ' + + ## --to-files with single source + + test_expect_success "ipfs add --to-files /mfspath succeeds" ' + mkdir -p mountdir && echo "Hello MFS!" > mountdir/mfs.txt && + ipfs add mountdir/mfs.txt --to-files /ipfs-add-to-files >actual + ' + + test_expect_success "ipfs add --to-files output looks good" ' + HASH_MFS="QmVT8bL3sGBA2TwvX8JPhrv5CYZL8LLLfW7mxkUjPZsgBr" && + echo "added $HASH_MFS mfs.txt" >expected && + test_cmp expected actual + ' + + test_expect_success "ipfs files read succeeds" ' + ipfs files read /ipfs-add-to-files >actual && + ipfs files rm /ipfs-add-to-files + ' + + test_expect_success "ipfs cat output looks good" ' + echo "Hello MFS!" >expected && + test_cmp expected actual + ' + + test_expect_success "ipfs add --to-files requires argument" ' + test_expect_code 1 ipfs add mountdir/mfs.txt --to-files >actual 2>&1 && + test_should_contain "Error: missing argument for option \"to-files\"" actual + ' + + test_expect_success "ipfs add --to-files / (MFS root) works" ' + echo "Hello MFS!" >expected && + ipfs add mountdir/mfs.txt --to-files / && + ipfs files read /mfs.txt >actual && + test_cmp expected actual && + ipfs files rm /mfs.txt && + rm mountdir/mfs.txt + ' + + ## --to-files with multiple sources + + test_expect_success "ipfs add file1 file2 --to-files /mfspath0 (without trailing slash) fails" ' + mkdir -p test && + echo "file1" > test/mfs1.txt && + echo "file2" > test/mfs2.txt && + test_expect_code 1 ipfs add test/mfs1.txt test/mfs2.txt --to-files /mfspath0 >actual 2>&1 && + test_should_contain "MFS destination is a file: only one entry can be copied to \"/mfspath0\"" actual && + ipfs files rm -r --force /mfspath0 + ' + + test_expect_success "ipfs add file1 file2 --to-files /mfsfile1 (without trailing slash + with preexisting file) fails" ' + echo test | ipfs files write --create /mfsfile1 && + test_expect_code 1 ipfs add test/mfs1.txt test/mfs2.txt --to-files /mfsfile1 >actual 2>&1 && + test_should_contain "Error: to-files: cannot put node in path \"/mfsfile1\"" actual && + ipfs files rm -r --force /mfsfile1 + ' + + test_expect_success "ipfs add file1 file2 --to-files /mfsdir1 (without trailing slash + with preexisting dir) fails" ' + ipfs files mkdir -p /mfsdir1 && + test_expect_code 1 ipfs add test/mfs1.txt test/mfs2.txt --to-files /mfsdir1 >actual 2>&1 && + test_should_contain "Error: to-files: cannot put node in path \"/mfsdir1\"" actual && + ipfs files rm -r --force /mfsdir1 + ' + + test_expect_success "ipfs add file1 file2 --to-files /mfsdir2/ (with trailing slash) succeeds" ' + ipfs files mkdir -p /mfsdir2 && + test_expect_code 0 ipfs add --cid-version 1 test/mfs1.txt test/mfs2.txt --to-files /mfsdir2/ > actual 2>&1 && + test_should_contain "added bafkreihm3rktn5z33luic3youqdsn326toaq3ekesmdvsa53sbrd3f5r3a mfs1.txt" actual && + test_should_contain "added bafkreidh5zkhr2vnwa2luwmuj24xo6l3jhfgvkgtk5cyp43oxs7owzpxby mfs2.txt" actual && + test_should_not_contain "Error" actual && + ipfs files ls /mfsdir2/ > lsout && + test_should_contain "mfs1.txt" lsout && + test_should_contain "mfs2.txt" lsout && + ipfs files rm -r --force /mfsdir2 + ' + + test_expect_success "ipfs add file1 file2 --to-files /mfsfile2/ (with trailing slash + with preexisting file) fails" ' + echo test | ipfs files write --create /mfsfile2 && + test_expect_code 1 ipfs add test/mfs1.txt test/mfs2.txt --to-files /mfsfile2/ >actual 2>&1 && + test_should_contain "Error: to-files: MFS destination \"/mfsfile2/\" is not a directory" actual && + ipfs files rm -r --force /mfsfile2 + ' + + ## --to-files with recursive dir + + # test MFS destination without trailing slash + test_expect_success "ipfs add with --to-files /mfs/subdir3 fails because /mfs/subdir3 exists" ' + ipfs files mkdir -p /mfs/subdir3 && + test_expect_code 1 ipfs add -r test --to-files /mfs/subdir3 >actual 2>&1 && + test_should_contain "cannot put node in path \"/mfs/subdir3\": directory already has entry by that name" actual && + ipfs files rm -r --force /mfs + ' + + # test recursive import of a dir into MFS subdirectory + test_expect_success "ipfs add -r dir --to-files /mfs/subdir4/ succeeds (because of trailing slash)" ' + ipfs files mkdir -p /mfs/subdir4 && + ipfs add --cid-version 1 -r test --to-files /mfs/subdir4/ >actual 2>&1 && + test_should_contain "added bafkreihm3rktn5z33luic3youqdsn326toaq3ekesmdvsa53sbrd3f5r3a test/mfs1.txt" actual && + test_should_contain "added bafkreidh5zkhr2vnwa2luwmuj24xo6l3jhfgvkgtk5cyp43oxs7owzpxby test/mfs2.txt" actual && + test_should_contain "added bafybeic7xwqwovt4g4bax6d3udp6222i63vj2rblpbim7uy2uw4a5gahha test" actual && + test_should_not_contain "Error" actual + ipfs files ls /mfs/subdir4/ > lsout && + test_should_contain "test" lsout && + test_should_not_contain "mfs1.txt" lsout && + test_should_not_contain "mfs2.txt" lsout && + ipfs files rm -r --force /mfs + ' + } test_add_cat_5MB() { diff --git a/test/sharness/t0041-ping.sh b/test/sharness/t0041-ping.sh index c4665b9ba..8fdfe1797 100755 --- a/test/sharness/t0041-ping.sh +++ b/test/sharness/t0041-ping.sh @@ -27,7 +27,7 @@ test_expect_success "test ping other" ' test_expect_success "test ping unreachable peer" ' printf "Looking up peer %s\n" "$BAD_PEER" > bad_ping_exp && - printf "Error: peer lookup failed: routing: not found\n" >> bad_ping_exp && + printf "PING QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJx.\nPing error: routing: not found\nError: ping failed\n" >> bad_ping_exp && ! ipfsi 0 ping -n2 -- "$BAD_PEER" > bad_ping_actual 2>&1 && test_cmp bad_ping_exp bad_ping_actual ' diff --git a/test/sharness/t0042-add-skip.sh b/test/sharness/t0042-add-skip.sh index 9da78163c..64d8e1a7c 100755 --- a/test/sharness/t0042-add-skip.sh +++ b/test/sharness/t0042-add-skip.sh @@ -93,6 +93,10 @@ EOF test_cmp expected actual ' + test_expect_failure "'ipfs add' with an unregistered hash and wrapped leaves fails without crashing" ' + ipfs add --hash poseidon-bls12_381-a2-fc1 --raw-leaves=false -r mountdir/planets + ' + } # should work offline diff --git a/test/sharness/t0109-gateway-web-_redirects-data/redirects.car b/test/sharness/t0109-gateway-web-_redirects-data/redirects.car new file mode 100644 index 000000000..ba4da8ba5 Binary files /dev/null and b/test/sharness/t0109-gateway-web-_redirects-data/redirects.car differ diff --git a/test/sharness/t0109-gateway-web-_redirects.sh b/test/sharness/t0109-gateway-web-_redirects.sh new file mode 100755 index 000000000..9ebfb911e --- /dev/null +++ b/test/sharness/t0109-gateway-web-_redirects.sh @@ -0,0 +1,239 @@ +#!/usr/bin/env bash + +test_description="Test HTTP Gateway _redirects support" + +. lib/test-lib.sh + +test_init_ipfs +test_launch_ipfs_daemon + +## ============================================================================ +## Test _redirects file support +## ============================================================================ + +# Import test case +# Run `ipfs cat /ipfs/$REDIRECTS_DIR_CID/_redirects` to see sample _redirects file +test_expect_success "Add the _redirects file test directory" ' + ipfs dag import ../t0109-gateway-web-_redirects-data/redirects.car +' +CAR_ROOT_CID=QmQyqMY5vUBSbSxyitJqthgwZunCQjDVtNd8ggVCxzuPQ4 + +REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/examples | cut -d "/" -f3) +REDIRECTS_DIR_HOSTNAME="${REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT" + +test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/redirect-one redirects with default of 301, per _redirects file" ' + curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/redirect-one" > response && + test_should_contain "301 Moved Permanently" response && + test_should_contain "Location: /one.html" response +' + +test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/301-redirect-one redirects with 301, per _redirects file" ' + curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/301-redirect-one" > response && + test_should_contain "301 Moved Permanently" response && + test_should_contain "Location: /one.html" response +' + +test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/302-redirect-two redirects with 302, per _redirects file" ' + curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/302-redirect-two" > response && + test_should_contain "302 Found" response && + test_should_contain "Location: /two.html" response +' + +test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/200-index returns 200, per _redirects file" ' + curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/200-index" > response && + test_should_contain "my index" response && + test_should_contain "200 OK" response +' + +test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/posts/:year/:month/:day/:title redirects with 301 and placeholders, per _redirects file" ' + curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/posts/2022/01/01/hello-world" > response && + test_should_contain "301 Moved Permanently" response && + test_should_contain "Location: /articles/2022/01/01/hello-world" response +' + +test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/splat/one.html redirects with 301 and splat placeholder, per _redirects file" ' + curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/splat/one.html" > response && + test_should_contain "301 Moved Permanently" response && + test_should_contain "Location: /redirected-splat/one.html" response +' + +# ensure custom 4xx works and has the same cache headers as regular /ipfs/ path +CUSTOM_4XX_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/examples/404.html | cut -d "/" -f3) +test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/not-found/has-no-redirects-entry returns custom 404, per _redirects file" ' + curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/not-found/has-no-redirects-entry" > response && + test_should_contain "404 Not Found" response && + test_should_contain "Cache-Control: public, max-age=29030400, immutable" response && + test_should_contain "Etag: \"$CUSTOM_4XX_CID\"" response && + test_should_contain "my 404" response +' + +CUSTOM_4XX_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/examples/410.html | cut -d "/" -f3) +test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/gone/has-no-redirects-entry returns custom 410, per _redirects file" ' + curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/gone/has-no-redirects-entry" > response && + test_should_contain "410 Gone" response && + test_should_contain "Cache-Control: public, max-age=29030400, immutable" response && + test_should_contain "Etag: \"$CUSTOM_4XX_CID\"" response && + test_should_contain "my 410" response +' + +CUSTOM_4XX_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/examples/451.html | cut -d "/" -f3) +test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/unavail/has-no-redirects-entry returns custom 451, per _redirects file" ' + curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/unavail/has-no-redirects-entry" > response && + test_should_contain "451 Unavailable For Legal Reasons" response && + test_should_contain "Cache-Control: public, max-age=29030400, immutable" response && + test_should_contain "Etag: \"$CUSTOM_4XX_CID\"" response && + test_should_contain "my 451" response +' + +test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/catch-all returns 200, per _redirects file" ' + curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/catch-all" > response && + test_should_contain "200 OK" response && + test_should_contain "my index" response +' + +# This test ensures _redirects is supported only on Web Gateways that use Host header (DNSLink, Subdomain) +test_expect_success "request for http://127.0.0.1:$GWAY_PORT/ipfs/$REDIRECTS_DIR_CID/301-redirect-one returns generic 404 (no custom 404 from _redirects since no origin isolation)" ' + curl -sD - "http://127.0.0.1:$GWAY_PORT/ipfs/$REDIRECTS_DIR_CID/301-redirect-one" > response && + test_should_contain "404 Not Found" response && + test_should_not_contain "my 404" response +' + +# With CRLF line terminator +NEWLINE_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/newlines | cut -d "/" -f3) +NEWLINE_REDIRECTS_DIR_HOSTNAME="${NEWLINE_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT" + +test_expect_success "newline: _redirects has CRLF line terminators" ' + ipfs cat /ipfs/$NEWLINE_REDIRECTS_DIR_CID/_redirects | file - > response && + test_should_contain "with CRLF line terminators" response +' + +test_expect_success "newline: request for $NEWLINE_REDIRECTS_DIR_HOSTNAME/redirect-one redirects with default of 301, per _redirects file" ' + curl -sD - --resolve $NEWLINE_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$NEWLINE_REDIRECTS_DIR_HOSTNAME/redirect-one" > response && + test_should_contain "301 Moved Permanently" response && + test_should_contain "Location: /one.html" response +' + +# Good codes +GOOD_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/good-codes | cut -d "/" -f3) +GOOD_REDIRECTS_DIR_HOSTNAME="${GOOD_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT" + +test_expect_success "good codes: request for $GOOD_REDIRECTS_DIR_HOSTNAME/redirect-one redirects with default of 301, per _redirects file" ' + curl -sD - --resolve $GOOD_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$GOOD_REDIRECTS_DIR_HOSTNAME/a301" > response && + test_should_contain "301 Moved Permanently" response && + test_should_contain "Location: /b301" response +' + +# Bad codes +BAD_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/bad-codes | cut -d "/" -f3) +BAD_REDIRECTS_DIR_HOSTNAME="${BAD_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT" + +# if accessing a path that doesn't exist, read _redirects and fail parsing, and return error +test_expect_success "bad codes: request for $BAD_REDIRECTS_DIR_HOSTNAME/not-found returns error about bad code" ' + curl -sD - --resolve $BAD_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$BAD_REDIRECTS_DIR_HOSTNAME/not-found" > response && + test_should_contain "500" response && + test_should_contain "status code 999 is not supported" response +' + +# if accessing a path that does exist, don't read _redirects and therefore don't fail parsing +test_expect_success "bad codes: request for $BAD_REDIRECTS_DIR_HOSTNAME/found.html doesn't return error about bad code" ' + curl -sD - --resolve $BAD_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$BAD_REDIRECTS_DIR_HOSTNAME/found.html" > response && + test_should_contain "200" response && + test_should_contain "my found" response && + test_should_not_contain "unsupported redirect status" response +' + +# Invalid file, containing "hello" +INVALID_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/invalid | cut -d "/" -f3) +INVALID_REDIRECTS_DIR_HOSTNAME="${INVALID_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT" + +# if accessing a path that doesn't exist, read _redirects and fail parsing, and return error +test_expect_success "invalid file: request for $INVALID_REDIRECTS_DIR_HOSTNAME/not-found returns error about invalid redirects file" ' + curl -sD - --resolve $INVALID_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$INVALID_REDIRECTS_DIR_HOSTNAME/not-found" > response && + test_should_contain "500" response && + test_should_contain "could not parse _redirects:" response +' + +# Invalid file, containing forced redirect +INVALID_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/forced | cut -d "/" -f3) +INVALID_REDIRECTS_DIR_HOSTNAME="${INVALID_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT" + +# if accessing a path that doesn't exist, read _redirects and fail parsing, and return error +test_expect_success "invalid file: request for $INVALID_REDIRECTS_DIR_HOSTNAME/not-found returns error about invalid redirects file" ' + curl -sD - --resolve $INVALID_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$INVALID_REDIRECTS_DIR_HOSTNAME/not-found" > response && + test_should_contain "500" response && + test_should_contain "could not parse _redirects:" response && + test_should_contain "forced redirects (or \"shadowing\") are not supported" response +' + +# if accessing a path that doesn't exist and _redirects file is too large, return error +TOO_LARGE_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/too-large | cut -d "/" -f3) +TOO_LARGE_REDIRECTS_DIR_HOSTNAME="${TOO_LARGE_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT" +test_expect_success "invalid file: request for $TOO_LARGE_REDIRECTS_DIR_HOSTNAME/not-found returns error about too large redirects file" ' + curl -sD - --resolve $TOO_LARGE_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$TOO_LARGE_REDIRECTS_DIR_HOSTNAME/not-found" > response && + test_should_contain "500" response && + test_should_contain "could not parse _redirects:" response && + test_should_contain "redirects file size cannot exceed" response +' + +test_kill_ipfs_daemon + +# disable wildcard DNSLink gateway +# and enable it on specific DNSLink hostname +ipfs config --json Gateway.NoDNSLink true && \ +ipfs config --json Gateway.PublicGateways '{ + "dnslink-enabled-on-fqdn.example.org": { + "NoDNSLink": false, + "UseSubdomains": false, + "Paths": ["/ipfs"] + }, + "dnslink-disabled-on-fqdn.example.com": { + "NoDNSLink": true, + "UseSubdomains": false, + "Paths": [] + } +}' || exit 1 + +# DNSLink test requires a daemon in online mode with precached /ipns/ mapping +# REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/examples | cut -d "/" -f3) +DNSLINK_FQDN="dnslink-enabled-on-fqdn.example.org" +NO_DNSLINK_FQDN="dnslink-disabled-on-fqdn.example.com" +export IPFS_NS_MAP="$DNSLINK_FQDN:/ipfs/$REDIRECTS_DIR_CID" + +# restart daemon to apply config changes +test_launch_ipfs_daemon + +# make sure test setup is valid (fail if CoreAPI is unable to resolve) +test_expect_success "spoofed DNSLink record resolves in cli" " + ipfs resolve /ipns/$DNSLINK_FQDN > result && + test_should_contain \"$REDIRECTS_DIR_CID\" result && + ipfs cat /ipns/$DNSLINK_FQDN/_redirects > result && + test_should_contain \"index.html\" result +" + +test_expect_success "request for $DNSLINK_FQDN/redirect-one redirects with default of 301, per _redirects file" ' + curl -sD - --resolve $DNSLINK_FQDN:$GWAY_PORT:127.0.0.1 "http://$DNSLINK_FQDN:$GWAY_PORT/redirect-one" > response && + test_should_contain "301 Moved Permanently" response && + test_should_contain "Location: /one.html" response +' + +# ensure custom 404 works and has the same cache headers as regular /ipns/ paths +test_expect_success "request for $DNSLINK_FQDN/en/has-no-redirects-entry returns custom 404, per _redirects file" ' + curl -sD - --resolve $DNSLINK_FQDN:$GWAY_PORT:127.0.0.1 "http://$DNSLINK_FQDN:$GWAY_PORT/not-found/has-no-redirects-entry" > response && + test_should_contain "404 Not Found" response && + test_should_contain "Etag: \"Qmd9GD7Bauh6N2ZLfNnYS3b7QVAijbud83b8GE8LPMNBBP\"" response && + test_should_not_contain "Cache-Control: public, max-age=29030400, immutable" response && + test_should_not_contain "immutable" response && + test_should_contain "Date: " response && + test_should_contain "my 404" response +' + +test_expect_success "request for $NO_DNSLINK_FQDN/redirect-one does not redirect, since DNSLink is disabled" ' + curl -sD - --resolve $NO_DNSLINK_FQDN:$GWAY_PORT:127.0.0.1 "http://$NO_DNSLINK_FQDN:$GWAY_PORT/redirect-one" > response && + test_should_not_contain "one.html" response && + test_should_not_contain "301 Moved Permanently" response && + test_should_not_contain "Location:" response +' + +test_kill_ipfs_daemon + +test_done diff --git a/test/sharness/t0114-gateway-subdomains.sh b/test/sharness/t0114-gateway-subdomains.sh index 0dad1e95c..a7e5a59c9 100755 --- a/test/sharness/t0114-gateway-subdomains.sh +++ b/test/sharness/t0114-gateway-subdomains.sh @@ -323,6 +323,38 @@ test_localhost_gateway_response_should_contain \ "http://api.localhost:$GWAY_PORT/api/v0/refs?arg=$DIR_CID&r=true" \ "Ref" +## ============================================================================ +## Test DNSLink inlining on HTTP gateways +## ============================================================================ + +# set explicit subdomain gateway config for the hostname +ipfs config --json Gateway.PublicGateways '{ + "localhost": { + "UseSubdomains": true, + "InlineDNSLink": true, + "Paths": ["/ipfs", "/ipns", "/api"] + }, + "example.com": { + "UseSubdomains": true, + "InlineDNSLink": true, + "Paths": ["/ipfs", "/ipns", "/api"] + } +}' || exit 1 +# restart daemon to apply config changes +test_kill_ipfs_daemon +test_launch_ipfs_daemon_without_network + +test_localhost_gateway_response_should_contain \ + "request for localhost/ipns/{fqdn} redirects to DNSLink in subdomain with DNS inlining" \ + "http://localhost:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \ + "Location: http://en-wikipedia--on--ipfs-org.ipns.localhost:$GWAY_PORT/wiki" + +test_hostname_gateway_response_should_contain \ + "request for example.com/ipns/{fqdn} redirects to DNSLink in subdomain with DNS inlining" \ + "example.com" \ + "http://127.0.0.1:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \ + "Location: http://en-wikipedia--on--ipfs-org.ipns.example.com/wiki" + ## ============================================================================ ## Test subdomain-based requests with a custom hostname config ## (origin per content root at http://*.example.com) diff --git a/test/sharness/t0116-prometheus-data/prometheus_metrics b/test/sharness/t0116-prometheus-data/prometheus_metrics index f6b5bccbc..32c0d8e43 100644 --- a/test/sharness/t0116-prometheus-data/prometheus_metrics +++ b/test/sharness/t0116-prometheus-data/prometheus_metrics @@ -159,10 +159,6 @@ flatfs_datastore_sync_latency_seconds_bucket flatfs_datastore_sync_latency_seconds_count flatfs_datastore_sync_latency_seconds_sum flatfs_datastore_sync_total -go_cgo_go_to_c_calls_calls_total -go_gc_cycles_automatic_gc_cycles_total -go_gc_cycles_forced_gc_cycles_total -go_gc_cycles_total_gc_cycles_total go_gc_duration_seconds go_gc_duration_seconds go_gc_duration_seconds @@ -170,77 +166,12 @@ go_gc_duration_seconds go_gc_duration_seconds go_gc_duration_seconds_count go_gc_duration_seconds_sum -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_bucket -go_gc_heap_allocs_by_size_bytes_total_count -go_gc_heap_allocs_by_size_bytes_total_sum -go_gc_heap_allocs_bytes_total -go_gc_heap_allocs_objects_total -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_bucket -go_gc_heap_frees_by_size_bytes_total_count -go_gc_heap_frees_by_size_bytes_total_sum -go_gc_heap_frees_bytes_total -go_gc_heap_frees_objects_total -go_gc_heap_goal_bytes -go_gc_heap_objects_objects -go_gc_heap_tiny_allocs_objects_total -go_gc_limiter_last_enabled_gc_cycle -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_bucket -go_gc_pauses_seconds_total_count -go_gc_pauses_seconds_total_sum -go_gc_stack_starting_size_bytes go_goroutines go_info -go_memory_classes_heap_free_bytes -go_memory_classes_heap_objects_bytes -go_memory_classes_heap_released_bytes -go_memory_classes_heap_stacks_bytes -go_memory_classes_heap_unused_bytes -go_memory_classes_metadata_mcache_free_bytes -go_memory_classes_metadata_mcache_inuse_bytes -go_memory_classes_metadata_mspan_free_bytes -go_memory_classes_metadata_mspan_inuse_bytes -go_memory_classes_metadata_other_bytes -go_memory_classes_os_stacks_bytes -go_memory_classes_other_bytes -go_memory_classes_profiling_buckets_bytes -go_memory_classes_total_bytes go_memstats_alloc_bytes go_memstats_alloc_bytes_total go_memstats_buck_hash_sys_bytes go_memstats_frees_total -go_memstats_gc_cpu_fraction go_memstats_gc_sys_bytes go_memstats_heap_alloc_bytes go_memstats_heap_idle_bytes @@ -260,21 +191,6 @@ go_memstats_other_sys_bytes go_memstats_stack_inuse_bytes go_memstats_stack_sys_bytes go_memstats_sys_bytes -go_sched_gomaxprocs_threads -go_sched_goroutines_goroutines -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_bucket -go_sched_latencies_seconds_count -go_sched_latencies_seconds_sum go_threads ipfs_bitswap_active_block_tasks ipfs_bitswap_active_tasks diff --git a/test/sharness/t0139-swarm-rcmgr.sh b/test/sharness/t0139-swarm-rcmgr.sh index 7d7ecef8c..3844c99bb 100755 --- a/test/sharness/t0139-swarm-rcmgr.sh +++ b/test/sharness/t0139-swarm-rcmgr.sh @@ -55,6 +55,10 @@ test_expect_success 'ResourceMgr enabled: swarm limit' ' jq -e .StreamsOutbound < json ' +test_expect_success 'connected: swarm stats all working properly' ' + test_expect_code 0 ipfs swarm stats all +' + # every scope has the same fields, so we only inspect System test_expect_success 'ResourceMgr enabled: swarm stats' ' ipfs swarm stats all --enc=json | tee json && diff --git a/test/sharness/t0191-webtransport-ping.sh b/test/sharness/t0191-webtransport-ping.sh new file mode 100755 index 000000000..82ef185e3 --- /dev/null +++ b/test/sharness/t0191-webtransport-ping.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +test_description="Test ping over WebTransport command" + +. lib/test-lib.sh + +test_init_ipfs + +# start iptb + wait for peering +test_expect_success 'init iptb' ' + iptb testbed create -type localipfs -count 2 -init +' + +addr1='"[\"/ip4/127.0.0.1/udp/0/quic/webtransport\"]"' +addr2='"[\"/ip4/127.0.0.1/udp/0/quic/webtransport\"]"' +test_expect_success "add WebTransport swarm addresses" ' + ipfsi 0 config --json Addresses.Swarm '$addr1' && + ipfsi 0 config --json Swarm.Transports.Network.WebTransport true && + ipfsi 1 config --json Addresses.Swarm '$addr2' && + ipfsi 1 config --json Swarm.Transports.Network.WebTransport true +' + +startup_cluster 2 + +test_expect_success 'peer ids' ' + PEERID_0=$(iptb attr get 0 id) && + PEERID_1=$(iptb attr get 1 id) +' + +test_expect_success "test ping other" ' + ipfsi 0 ping -n2 -- "$PEERID_1" && + ipfsi 1 ping -n2 -- "$PEERID_0" +' + +test_expect_success "test ping self" ' + test_must_fail ipfsi 0 ping -n2 -- "$PEERID_0" && + test_must_fail ipfsi 1 ping -n2 -- "$PEERID_1" +' + +test_expect_success "test ping 0" ' + test_must_fail ipfsi 0 ping -n0 -- "$PEERID_1" && + test_must_fail ipfsi 1 ping -n0 -- "$PEERID_0" +' + +test_expect_success 'stop iptb' ' + iptb stop +' + +test_done diff --git a/test/sharness/t0191-noise.sh b/test/sharness/t0195-noise.sh similarity index 100% rename from test/sharness/t0191-noise.sh rename to test/sharness/t0195-noise.sh diff --git a/test/sharness/t0320-pubsub.sh b/test/sharness/t0320-pubsub.sh index 676d890c2..5635b842e 100755 --- a/test/sharness/t0320-pubsub.sh +++ b/test/sharness/t0320-pubsub.sh @@ -158,7 +158,7 @@ test_expect_success 'pubsub cmd fails because it was disabled via cli flag' ' ' test_expect_success "pubsub cmd produces error" ' - echo "Error: experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use." > expected && + echo "Error: experimental pubsub feature not enabled, run daemon with --enable-pubsub-experiment to use" > expected && test_cmp expected pubsub_cmd_out ' diff --git a/test/sharness/t0701-delegated-routing-reframe.sh b/test/sharness/t0701-delegated-routing-reframe.sh index 424be6ef5..5070b4fff 100755 --- a/test/sharness/t0701-delegated-routing-reframe.sh +++ b/test/sharness/t0701-delegated-routing-reframe.sh @@ -66,13 +66,81 @@ test_expect_success "no routers means findprovs returns no results" ' test_kill_ipfs_daemon +ipfs config Routing.Type --json '"custom"' || exit 1 +ipfs config Routing.Methods --json '{ + "find-peers": { + "RouterName": "TestDelegatedRouter" + }, + "find-providers": { + "RouterName": "TestDelegatedRouter" + }, + "get-ipns": { + "RouterName": "TestDelegatedRouter" + }, + "provide": { + "RouterName": "TestDelegatedRouter" + } + }' || exit 1 + +test_expect_success "missing method params makes daemon fails" ' + echo "Error: constructing the node (see log for full detail): method name \"put-ipns\" is missing from Routing.Methods config param" > expected_error && + GOLOG_LOG_LEVEL=fatal ipfs daemon 2> actual_error || exit 0 && + test_cmp expected_error actual_error +' + +ipfs config Routing.Methods --json '{ + "find-peers": { + "RouterName": "TestDelegatedRouter" + }, + "find-providers": { + "RouterName": "TestDelegatedRouter" + }, + "get-ipns": { + "RouterName": "TestDelegatedRouter" + }, + "provide": { + "RouterName": "TestDelegatedRouter" + }, + "put-ipns": { + "RouterName": "TestDelegatedRouter" + }, + "NOT_SUPPORTED": { + "RouterName": "TestDelegatedRouter" + } + }' || exit 1 + +test_expect_success "having wrong methods makes daemon fails" ' + echo "Error: constructing the node (see log for full detail): method name \"NOT_SUPPORTED\" is not a supported method on Routing.Methods config param" > expected_error && + GOLOG_LOG_LEVEL=fatal ipfs daemon 2> actual_error || exit 0 && + test_cmp expected_error actual_error +' + # set Routing config to only use delegated routing via mocked reframe endpoint + +ipfs config Routing.Type --json '"custom"' || exit 1 ipfs config Routing.Routers.TestDelegatedRouter --json '{ "Type": "reframe", "Parameters": { "Endpoint": "http://127.0.0.1:5098/reframe" } }' || exit 1 +ipfs config Routing.Methods --json '{ + "find-peers": { + "RouterName": "TestDelegatedRouter" + }, + "find-providers": { + "RouterName": "TestDelegatedRouter" + }, + "get-ipns": { + "RouterName": "TestDelegatedRouter" + }, + "provide": { + "RouterName": "TestDelegatedRouter" + }, + "put-ipns": { + "RouterName": "TestDelegatedRouter" + } + }' || exit 1 test_expect_success "adding reframe endpoint to Routing.Routers config works" ' echo "http://127.0.0.1:5098/reframe" > expected && diff --git a/version.go b/version.go index 5dba62299..7639d27da 100644 --- a/version.go +++ b/version.go @@ -11,9 +11,9 @@ import ( var CurrentCommit string // CurrentVersionNumber is the current application's version literal -const CurrentVersionNumber = "0.16.0-dev" +const CurrentVersionNumber = "0.17.0-dev" -const ApiVersion = "/kubo/" + CurrentVersionNumber + "/" +const ApiVersion = "/kubo/" + CurrentVersionNumber + "/" //nolint // GetUserAgentVersion is the libp2p user agent used by go-ipfs. //