mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-21 10:27:46 +08:00
Extract the namesys and the keystore submodules
Namesys is a very useful submodule. Given a ValueStore and a Datastore it can resolve and publish /ipns/ paths. This functionality does not need to be sequestered inside go-ipfs as it can and should be used without IPFS, for example, for implementing lightweight IPNS publishing services or for resolving /ipns/ paths. "keystore" extraction was necessary, as there is a dependency to it in namesys. Keystore is also a useful module by itself within the stack. Fixes #6537
This commit is contained in:
parent
4d262b1f73
commit
3db9551f79
@ -14,8 +14,8 @@ import (
|
||||
oldcmds "github.com/ipfs/go-ipfs/commands"
|
||||
core "github.com/ipfs/go-ipfs/core"
|
||||
"github.com/ipfs/go-ipfs/core/commands"
|
||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
||||
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
|
||||
namesys "github.com/ipfs/go-namesys"
|
||||
|
||||
cmds "github.com/ipfs/go-ipfs-cmds"
|
||||
config "github.com/ipfs/go-ipfs-config"
|
||||
|
||||
@ -3,7 +3,7 @@ package commands
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-ipfs/namesys"
|
||||
"github.com/ipfs/go-namesys"
|
||||
|
||||
ipns "github.com/ipfs/go-ipns"
|
||||
"github.com/libp2p/go-libp2p-core/test"
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
|
||||
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
|
||||
ncmd "github.com/ipfs/go-ipfs/core/commands/name"
|
||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
||||
namesys "github.com/ipfs/go-namesys"
|
||||
nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
|
||||
|
||||
cmds "github.com/ipfs/go-ipfs-cmds"
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
|
||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
||||
namesys "github.com/ipfs/go-namesys"
|
||||
|
||||
cmds "github.com/ipfs/go-ipfs-cmds"
|
||||
logging "github.com/ipfs/go-log"
|
||||
|
||||
@ -9,7 +9,7 @@ import (
|
||||
|
||||
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
|
||||
ncmd "github.com/ipfs/go-ipfs/core/commands/name"
|
||||
ns "github.com/ipfs/go-ipfs/namesys"
|
||||
ns "github.com/ipfs/go-namesys"
|
||||
|
||||
cidenc "github.com/ipfs/go-cidutil/cidenc"
|
||||
cmds "github.com/ipfs/go-ipfs-cmds"
|
||||
|
||||
@ -45,11 +45,11 @@ import (
|
||||
"github.com/ipfs/go-ipfs/core/node"
|
||||
"github.com/ipfs/go-ipfs/core/node/libp2p"
|
||||
"github.com/ipfs/go-ipfs/fuse/mount"
|
||||
"github.com/ipfs/go-ipfs/namesys"
|
||||
ipnsrp "github.com/ipfs/go-ipfs/namesys/republisher"
|
||||
"github.com/ipfs/go-ipfs/p2p"
|
||||
"github.com/ipfs/go-ipfs/peering"
|
||||
"github.com/ipfs/go-ipfs/repo"
|
||||
"github.com/ipfs/go-namesys"
|
||||
ipnsrp "github.com/ipfs/go-namesys/republisher"
|
||||
)
|
||||
|
||||
var log = logging.Logger("core")
|
||||
|
||||
@ -39,8 +39,8 @@ import (
|
||||
|
||||
"github.com/ipfs/go-ipfs/core"
|
||||
"github.com/ipfs/go-ipfs/core/node"
|
||||
"github.com/ipfs/go-ipfs/namesys"
|
||||
"github.com/ipfs/go-ipfs/repo"
|
||||
"github.com/ipfs/go-namesys"
|
||||
)
|
||||
|
||||
type CoreAPI struct {
|
||||
|
||||
@ -6,8 +6,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-ipfs/keystore"
|
||||
"github.com/ipfs/go-ipfs/namesys"
|
||||
"github.com/ipfs/go-ipfs-keystore"
|
||||
"github.com/ipfs/go-namesys"
|
||||
|
||||
ipath "github.com/ipfs/go-path"
|
||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||
|
||||
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
gopath "path"
|
||||
|
||||
"github.com/ipfs/go-ipfs/namesys/resolve"
|
||||
"github.com/ipfs/go-namesys/resolve"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
ipld "github.com/ipfs/go-ipld-format"
|
||||
|
||||
@ -9,12 +9,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-filestore"
|
||||
"github.com/ipfs/go-ipfs-keystore"
|
||||
"github.com/ipfs/go-ipfs/core"
|
||||
"github.com/ipfs/go-ipfs/core/bootstrap"
|
||||
"github.com/ipfs/go-ipfs/core/coreapi"
|
||||
mock "github.com/ipfs/go-ipfs/core/mock"
|
||||
"github.com/ipfs/go-ipfs/core/node/libp2p"
|
||||
"github.com/ipfs/go-ipfs/keystore"
|
||||
"github.com/ipfs/go-ipfs/repo"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
|
||||
@ -14,8 +14,8 @@ import (
|
||||
version "github.com/ipfs/go-ipfs"
|
||||
core "github.com/ipfs/go-ipfs/core"
|
||||
"github.com/ipfs/go-ipfs/core/coreapi"
|
||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
||||
repo "github.com/ipfs/go-ipfs/repo"
|
||||
namesys "github.com/ipfs/go-namesys"
|
||||
|
||||
datastore "github.com/ipfs/go-datastore"
|
||||
syncds "github.com/ipfs/go-datastore/sync"
|
||||
|
||||
@ -12,7 +12,7 @@ import (
|
||||
cid "github.com/ipfs/go-cid"
|
||||
core "github.com/ipfs/go-ipfs/core"
|
||||
coreapi "github.com/ipfs/go-ipfs/core/coreapi"
|
||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
||||
namesys "github.com/ipfs/go-namesys"
|
||||
isd "github.com/jbenet/go-is-domain"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
mbase "github.com/multiformats/go-multibase"
|
||||
|
||||
@ -11,9 +11,9 @@ import (
|
||||
"github.com/libp2p/go-libp2p-core/routing"
|
||||
"github.com/libp2p/go-libp2p-record"
|
||||
|
||||
"github.com/ipfs/go-ipfs/namesys"
|
||||
"github.com/ipfs/go-ipfs/namesys/republisher"
|
||||
"github.com/ipfs/go-ipfs/repo"
|
||||
"github.com/ipfs/go-namesys"
|
||||
"github.com/ipfs/go-namesys/republisher"
|
||||
)
|
||||
|
||||
const DefaultIpnsCacheSize = 128
|
||||
|
||||
@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/go-ipfs/core"
|
||||
nsys "github.com/ipfs/go-ipfs/namesys"
|
||||
nsys "github.com/ipfs/go-namesys"
|
||||
path "github.com/ipfs/go-path"
|
||||
ft "github.com/ipfs/go-unixfs"
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
|
||||
8
go.mod
8
go.mod
@ -4,7 +4,6 @@ require (
|
||||
bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.2.0
|
||||
github.com/blang/semver/v4 v4.0.0
|
||||
github.com/bren2010/proquint v0.0.0-20201027163346-95122a84635f
|
||||
github.com/cheggaaa/pb v1.0.29
|
||||
github.com/coreos/go-systemd/v22 v22.1.0
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
@ -12,9 +11,7 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/gabriel-vasile/mimetype v1.1.2
|
||||
github.com/go-bindata/go-bindata/v3 v3.1.3
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/hashicorp/go-multierror v1.1.0
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/ipfs/go-bitswap v0.3.3
|
||||
github.com/ipfs/go-block-format v0.0.3
|
||||
github.com/ipfs/go-blockservice v0.1.4
|
||||
@ -33,10 +30,10 @@ require (
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.5
|
||||
github.com/ipfs/go-ipfs-cmds v0.6.0
|
||||
github.com/ipfs/go-ipfs-config v0.12.0
|
||||
github.com/ipfs/go-ipfs-ds-help v0.1.1
|
||||
github.com/ipfs/go-ipfs-exchange-interface v0.0.1
|
||||
github.com/ipfs/go-ipfs-exchange-offline v0.0.1
|
||||
github.com/ipfs/go-ipfs-files v0.0.8
|
||||
github.com/ipfs/go-ipfs-keystore v0.0.2
|
||||
github.com/ipfs/go-ipfs-pinner v0.1.1
|
||||
github.com/ipfs/go-ipfs-posinfo v0.0.1
|
||||
github.com/ipfs/go-ipfs-provider v0.4.3
|
||||
@ -51,6 +48,7 @@ require (
|
||||
github.com/ipfs/go-metrics-interface v0.0.1
|
||||
github.com/ipfs/go-metrics-prometheus v0.0.2
|
||||
github.com/ipfs/go-mfs v0.1.2
|
||||
github.com/ipfs/go-namesys v0.0.1
|
||||
github.com/ipfs/go-path v0.0.9
|
||||
github.com/ipfs/go-pinning-service-http-client v0.1.0
|
||||
github.com/ipfs/go-unixfs v0.2.4
|
||||
@ -86,7 +84,6 @@ require (
|
||||
github.com/libp2p/go-tcp-transport v0.2.1
|
||||
github.com/libp2p/go-ws-transport v0.4.0
|
||||
github.com/lucas-clemente/quic-go v0.19.3
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/multiformats/go-multiaddr v0.3.1
|
||||
github.com/multiformats/go-multiaddr-dns v0.2.0
|
||||
@ -97,7 +94,6 @@ require (
|
||||
github.com/prometheus/client_golang v1.9.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc
|
||||
github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1
|
||||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7
|
||||
github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b
|
||||
|
||||
96
go.sum
96
go.sum
@ -40,6 +40,7 @@ github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/Stebalien/go-bitfield v0.0.0-20180330043415-076a62f9ce6e/go.mod h1:3oM7gXIttpYDAJXpVNnSCiUMYBLIZ6cb1t+Ip982MRo=
|
||||
github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo=
|
||||
github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
@ -73,11 +74,13 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/bren2010/proquint v0.0.0-20201027163346-95122a84635f h1:aYq2dAS53HXEmxlI9AAggLbqJS4DML1/H0+r59TH/vw=
|
||||
github.com/bren2010/proquint v0.0.0-20201027163346-95122a84635f/go.mod h1:Jbj8eKecMNwf0KFI75skSUZqMB4UCRcndUScVBTWyUI=
|
||||
github.com/bren2010/proquint v0.0.0-20160323162903-38337c27106d h1:QgeLLoPD3kRVmeu/1al9iIpIANMi9O1zXFm8BnYGCJg=
|
||||
github.com/bren2010/proquint v0.0.0-20160323162903-38337c27106d/go.mod h1:Jbj8eKecMNwf0KFI75skSUZqMB4UCRcndUScVBTWyUI=
|
||||
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
|
||||
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||
github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||
@ -171,6 +174,7 @@ github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:Jp
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as=
|
||||
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ=
|
||||
@ -181,6 +185,7 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gabriel-vasile/mimetype v1.1.1/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
|
||||
github.com/gabriel-vasile/mimetype v1.1.2 h1:gaPnPcNor5aZSVCJVSGipcpbgMWiAAj9z182ocSGbHU=
|
||||
github.com/gabriel-vasile/mimetype v1.1.2/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@ -285,6 +290,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
||||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
||||
github.com/gxed/pubsub v0.0.0-20180201040156-26ebdf44f824/go.mod h1:OiEWyHgK+CWrmOlVquHaIK1vhpUJydC9m0Je6mhaiNE=
|
||||
github.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8=
|
||||
github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY=
|
||||
github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY=
|
||||
@ -316,6 +322,7 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
|
||||
github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=
|
||||
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
|
||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
@ -325,17 +332,20 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod
|
||||
github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI=
|
||||
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
|
||||
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
|
||||
github.com/ipfs/go-bitswap v0.0.3/go.mod h1:jadAZYsP/tcRMl47ZhFxhaNuDQoXawT8iHMg+iFoQbg=
|
||||
github.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3UPrwvis=
|
||||
github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0=
|
||||
github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs=
|
||||
github.com/ipfs/go-bitswap v0.1.3/go.mod h1:YEQlFy0kkxops5Vy+OxWdRSEZIoS7I7KDIwoa5Chkps=
|
||||
github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM=
|
||||
github.com/ipfs/go-bitswap v0.2.20/go.mod h1:C7TwBgHnu89Q8sHsTJP7IhUqF9XYLe71P4tT5adgmYo=
|
||||
github.com/ipfs/go-bitswap v0.3.3 h1:CrTO3OiOYFBcdliw074/C7T2QYHEOsPClgvR6RIYcO4=
|
||||
github.com/ipfs/go-bitswap v0.3.3/go.mod h1:AyWWfN3moBzQX0banEtfKOfbXb3ZeoOeXnZGNPV9S6w=
|
||||
github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc=
|
||||
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
|
||||
github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc=
|
||||
github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
|
||||
github.com/ipfs/go-blockservice v0.0.3/go.mod h1:/NNihwTi6V2Yr6g8wBI+BSwPuURpBRMtYNGrlxZ8KuI=
|
||||
github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So=
|
||||
github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M=
|
||||
github.com/ipfs/go-blockservice v0.1.1/go.mod h1:t+411r7psEUhLueM8C7aPA7cxCclv4O3VsUVxt9kz2I=
|
||||
@ -371,6 +381,7 @@ github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaH
|
||||
github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=
|
||||
github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE=
|
||||
github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=
|
||||
github.com/ipfs/go-ds-badger v0.2.4/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=
|
||||
github.com/ipfs/go-ds-badger v0.2.6 h1:Hy8jw4rifxtRDrqpvC1yh36oIyE37KDzsUzlHUPOFiU=
|
||||
github.com/ipfs/go-ds-badger v0.2.6/go.mod h1:02rnztVKA4aZwDuaRPTf8mpqcKmXP7mLl6JPxd14JHA=
|
||||
github.com/ipfs/go-ds-flatfs v0.4.5 h1:4QceuKEbH+HVZ2ZommstJMi3o3II+dWS3IhLaD7IGHs=
|
||||
@ -386,8 +397,10 @@ github.com/ipfs/go-filestore v0.0.3 h1:MhZ1jT5K3NewZwim6rS/akcJLm1xM+r6nz6foeB9E
|
||||
github.com/ipfs/go-filestore v0.0.3/go.mod h1:dvXRykFzyyXN2CdNlRGzDAkXMDPyI+D7JE066SiKLSE=
|
||||
github.com/ipfs/go-fs-lock v0.0.6 h1:sn3TWwNVQqSeNjlWy6zQ1uUGAZrV3hPOyEA6y1/N2a0=
|
||||
github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28L7zESmM=
|
||||
github.com/ipfs/go-graphsync v0.1.1/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE=
|
||||
github.com/ipfs/go-graphsync v0.7.0 h1:ZdyU2otZYPjcvduAPwVjCdijmkPtHI1mm1VyZbRQ5KI=
|
||||
github.com/ipfs/go-graphsync v0.7.0/go.mod h1:YRQg0TyvD2HzFansAZdMcUFBJ8zIJ4K+32kNdnHfHZc=
|
||||
github.com/ipfs/go-ipfs v0.7.0/go.mod h1:4UNBZMgbAZ6/+xUZDlMkGxMFPiu1RB67+TaNVvKV7ZQ=
|
||||
github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08=
|
||||
github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw=
|
||||
github.com/ipfs/go-ipfs-blockstore v0.1.4 h1:2SGI6U1B44aODevza8Rde3+dY30Pb+lbcObe1LETxOQ=
|
||||
@ -397,8 +410,10 @@ github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtL
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw=
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8=
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8=
|
||||
github.com/ipfs/go-ipfs-cmds v0.4.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk=
|
||||
github.com/ipfs/go-ipfs-cmds v0.6.0 h1:yAxdowQZzoFKjcLI08sXVNnqVj3jnABbf9smrPQmBsw=
|
||||
github.com/ipfs/go-ipfs-cmds v0.6.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk=
|
||||
github.com/ipfs/go-ipfs-config v0.9.0/go.mod h1:GQUxqb0NfkZmEU92PxqqqLVVFTLpoGGUlBaTyDaAqrE=
|
||||
github.com/ipfs/go-ipfs-config v0.12.0 h1:wxqN3ohBlis1EkhkzIKuF+XLx4YNn9rNpiSOYw3DFZc=
|
||||
github.com/ipfs/go-ipfs-config v0.12.0/go.mod h1:Ei/FLgHGTdPyqCPK0oPCwGTe8VSnsjJjx7HZqUb6Ry0=
|
||||
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
|
||||
@ -411,9 +426,14 @@ github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6r
|
||||
github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM=
|
||||
github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew=
|
||||
github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0=
|
||||
github.com/ipfs/go-ipfs-files v0.0.2/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=
|
||||
github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=
|
||||
github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg=
|
||||
github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs=
|
||||
github.com/ipfs/go-ipfs-flags v0.0.1/go.mod h1:RnXBb9WV53GSfTrSDVK61NLTFKvWc60n+K9EgCDh+rA=
|
||||
github.com/ipfs/go-ipfs-keystore v0.0.2 h1:Fa9xg9IFD1VbiZtrNLzsD0GuELVHUFXCWF64kCPfEXU=
|
||||
github.com/ipfs/go-ipfs-keystore v0.0.2/go.mod h1:H49tRmibOEs7gLMgbOsjC4dqh1u5e0R/SWuc2ScfgSo=
|
||||
github.com/ipfs/go-ipfs-pinner v0.0.4/go.mod h1:s4kFZWLWGDudN8Jyd/GTpt222A12C2snA2+OTdy/7p8=
|
||||
github.com/ipfs/go-ipfs-pinner v0.1.1 h1:iJd1gwILGQJSZhhI0jn6yFOLg34Ua7fdKcB6mXp6k/M=
|
||||
github.com/ipfs/go-ipfs-pinner v0.1.1/go.mod h1:EzyyaWCWeZJ/he9cDBH6QrEkSuRqTRWMmCoyNkylTTg=
|
||||
github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs=
|
||||
@ -429,6 +449,7 @@ github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42
|
||||
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
|
||||
github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8=
|
||||
github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=
|
||||
github.com/ipfs/go-ipld-cbor v0.0.1/go.mod h1:RXHr8s4k0NE0TKhnrxqZC9M888QfsBN9rhS5NjfKzY8=
|
||||
github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc=
|
||||
github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc=
|
||||
github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4=
|
||||
@ -454,6 +475,7 @@ github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBW
|
||||
github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
|
||||
github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0=
|
||||
github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
||||
github.com/ipfs/go-merkledag v0.0.3/go.mod h1:Oc5kIXLHokkE1hWGMBHw+oxehkAaTOqtEb7Zbh6BhLA=
|
||||
github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto=
|
||||
github.com/ipfs/go-merkledag v0.1.0/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk=
|
||||
github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk=
|
||||
@ -467,7 +489,11 @@ github.com/ipfs/go-metrics-prometheus v0.0.2 h1:9i2iljLg12S78OhC6UAiXi176xvQGiZa
|
||||
github.com/ipfs/go-metrics-prometheus v0.0.2/go.mod h1:ELLU99AQQNi+zX6GCGm2lAgnzdSH3u5UVlCdqSXnEks=
|
||||
github.com/ipfs/go-mfs v0.1.2 h1:DlelNSmH+yz/Riy0RjPKlooPg0KML4lXGdLw7uZkfAg=
|
||||
github.com/ipfs/go-mfs v0.1.2/go.mod h1:T1QBiZPEpkPLzDqEJLNnbK55BVKVlNi2a+gVm4diFo0=
|
||||
github.com/ipfs/go-namesys v0.0.1 h1:HmhgHDA2hyfVtFtbvPR92IdmKbUFRmlbU0Lv1IwmDas=
|
||||
github.com/ipfs/go-namesys v0.0.1/go.mod h1:I33kVZixNRWXe5FN1mpWBXsAeJj0t+kxcVDgbIkgE2E=
|
||||
github.com/ipfs/go-path v0.0.3/go.mod h1:zIRQUez3LuQIU25zFjC2hpBTHimWx7VK5bjZgRLbbdo=
|
||||
github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno=
|
||||
github.com/ipfs/go-path v0.0.8/go.mod h1:VpDkSBKQ9EFQOUgi54Tq/O/tGi8n1RfYNks13M3DEs8=
|
||||
github.com/ipfs/go-path v0.0.9 h1:BIi831cNED8YnIlIKo9y1SI3u+E+FwQQD+rIIw8PwFA=
|
||||
github.com/ipfs/go-path v0.0.9/go.mod h1:VpDkSBKQ9EFQOUgi54Tq/O/tGi8n1RfYNks13M3DEs8=
|
||||
github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ=
|
||||
@ -477,19 +503,25 @@ github.com/ipfs/go-peertaskqueue v0.2.0 h1:2cSr7exUGKYyDeUyQ7P/nHPs9P7Ht/B+ROrpN
|
||||
github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY=
|
||||
github.com/ipfs/go-pinning-service-http-client v0.1.0 h1:Au0P4NglL5JfzhNSZHlZ1qra+IcJyO3RWMd9EYCwqSY=
|
||||
github.com/ipfs/go-pinning-service-http-client v0.1.0/go.mod h1:tcCKmlkWWH9JUUkKs8CrOZBanacNc1dmKLfjlyXAMu4=
|
||||
github.com/ipfs/go-unixfs v0.0.4/go.mod h1:eIo/p9ADu/MFOuyxzwU+Th8D6xoxU//r590vUpWyfz8=
|
||||
github.com/ipfs/go-unixfs v0.1.0/go.mod h1:lysk5ELhOso8+Fed9U1QTGey2ocsfaZ18h0NCO2Fj9s=
|
||||
github.com/ipfs/go-unixfs v0.2.4 h1:6NwppOXefWIyysZ4LR/qUBPvXd5//8J3jiMdvpbw6Lo=
|
||||
github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw=
|
||||
github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E=
|
||||
github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0=
|
||||
github.com/ipfs/interface-go-ipfs-core v0.3.0/go.mod h1:Tihp8zxGpUeE3Tokr94L6zWZZdkRQvG5TL6i9MuNE+s=
|
||||
github.com/ipfs/interface-go-ipfs-core v0.4.0 h1:+mUiamyHIwedqP8ZgbCIwpy40oX7QcXUbo4CZOeJVJg=
|
||||
github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o=
|
||||
github.com/ipld/go-car v0.1.1-0.20200429200904-c222d793c339/go.mod h1:eajxljm6I8o3LitnFeVEmucwZmz7+yLSiKce9yYMefg=
|
||||
github.com/ipld/go-car v0.2.0 h1:WwP83IdXdEuaW4fkCj+DWmdWygcFXpixramvItqFo1A=
|
||||
github.com/ipld/go-car v0.2.0/go.mod h1:pPb7hzVBHBoRqU3GkPy1d6FZKQoGQ56yd3MyPGzZ0Xs=
|
||||
github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8=
|
||||
github.com/ipld/go-ipld-prime v0.7.0 h1:eigF1ZpaL1prbsKYVMqPLoPJqD/pzkQOe2j1uzvVg7w=
|
||||
github.com/ipld/go-ipld-prime v0.7.0/go.mod h1:0xEgdD6MKbZ1vF0GC+YcR/C4SQCAlRuOjIJ2i0HxqzM=
|
||||
github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs=
|
||||
github.com/ipld/go-ipld-prime-proto v0.1.1 h1:EX4yWYaIqSLwtVE30nxEcZDcvsWDtx1vImSG+XCJebY=
|
||||
github.com/ipld/go-ipld-prime-proto v0.1.1/go.mod h1:cI9NwYAUKCLUwqufoUjChISxuTEkaY2yvNYCRCuhRck=
|
||||
github.com/jackpal/gateway v1.0.4/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
|
||||
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
|
||||
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
@ -556,6 +588,7 @@ github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoR
|
||||
github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c=
|
||||
github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=
|
||||
github.com/libp2p/go-conn-security v0.0.1/go.mod h1:bGmu51N0KU9IEjX7kl2PQjgZa40JQWnayTvNMgD/vyk=
|
||||
github.com/libp2p/go-conn-security-multistream v0.0.1/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE=
|
||||
github.com/libp2p/go-conn-security-multistream v0.0.2/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE=
|
||||
github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc=
|
||||
github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M=
|
||||
@ -567,35 +600,45 @@ github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZ
|
||||
github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
|
||||
github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=
|
||||
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
|
||||
github.com/libp2p/go-libp2p v0.0.2/go.mod h1:Qu8bWqFXiocPloabFGUcVG4kk94fLvfC8mWTDdFC9wE=
|
||||
github.com/libp2p/go-libp2p v0.0.30/go.mod h1:XWT8FGHlhptAv1+3V/+J5mEpzyui/5bvFsNuWYs611A=
|
||||
github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM=
|
||||
github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8=
|
||||
github.com/libp2p/go-libp2p v0.6.0/go.mod h1:mfKWI7Soz3ABX+XEBR61lGbg+ewyMtJHVt043oWeqwg=
|
||||
github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54=
|
||||
github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k=
|
||||
github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw=
|
||||
github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o=
|
||||
github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM=
|
||||
github.com/libp2p/go-libp2p v0.11.0/go.mod h1:3/ogJDXsbbepEfqtZKBR/DedzxJXCeK17t2Z9RE9bEE=
|
||||
github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0=
|
||||
github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s=
|
||||
github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052 h1:BM7aaOF7RpmNn9+9g6uTjGJ0cTzWr5j9i9IKeun2M8U=
|
||||
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-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4=
|
||||
github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE=
|
||||
github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8=
|
||||
github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=
|
||||
github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI=
|
||||
github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI=
|
||||
github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A=
|
||||
github.com/libp2p/go-libp2p-autonat v0.3.2/go.mod h1:0OzOi1/cVc7UcxfOddemYD5vzEqi4fwRbnZcJGLi68U=
|
||||
github.com/libp2p/go-libp2p-autonat v0.4.0 h1:3y8XQbpr+ssX8QfZUHekjHCYK64sj6/4hnf/awD4+Ug=
|
||||
github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk=
|
||||
github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc=
|
||||
github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro=
|
||||
github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU=
|
||||
github.com/libp2p/go-libp2p-blankhost v0.1.6/go.mod h1:jONCAJqEP+Z8T6EQviGL4JsQcLx1LgTGtVqFNY8EMfQ=
|
||||
github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk=
|
||||
github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ=
|
||||
github.com/libp2p/go-libp2p-circuit v0.0.1/go.mod h1:Dqm0s/BiV63j8EEAs8hr1H5HudqvCAeXxDyic59lCwE=
|
||||
github.com/libp2p/go-libp2p-circuit v0.0.9/go.mod h1:uU+IBvEQzCu953/ps7bYzC/D/R0Ho2A9LfKVVCatlqU=
|
||||
github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8=
|
||||
github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU=
|
||||
github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo=
|
||||
github.com/libp2p/go-libp2p-circuit v0.2.2/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4=
|
||||
github.com/libp2p/go-libp2p-circuit v0.3.1/go.mod h1:8RMIlivu1+RxhebipJwFDA45DasLx+kkrp4IlJj53F4=
|
||||
github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc=
|
||||
github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA=
|
||||
github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w=
|
||||
@ -613,6 +656,7 @@ github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUh
|
||||
github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=
|
||||
github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=
|
||||
github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
|
||||
github.com/libp2p/go-libp2p-core v0.5.2/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
|
||||
github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
|
||||
github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
|
||||
github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM=
|
||||
@ -628,22 +672,27 @@ github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJB
|
||||
github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE=
|
||||
github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I=
|
||||
github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=
|
||||
github.com/libp2p/go-libp2p-discovery v0.0.1/go.mod h1:ZkkF9xIFRLA1xCc7bstYFkd80gBGK8Fc1JqGoU2i+zI=
|
||||
github.com/libp2p/go-libp2p-discovery v0.0.5/go.mod h1:YtF20GUxjgoKZ4zmXj8j3Nb2TUSBHFlOCetzYdbZL5I=
|
||||
github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g=
|
||||
github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg=
|
||||
github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw=
|
||||
github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4=
|
||||
github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ=
|
||||
github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=
|
||||
github.com/libp2p/go-libp2p-gostream v0.2.1/go.mod h1:1Mjp3LDmkqICe5tH9yLVNCqFaRTy6OwBvuJV6j1b9Nk=
|
||||
github.com/libp2p/go-libp2p-gostream v0.3.0 h1:rnas//vRdHYCr7bjraZJISPwZV8OGMjeX5k5fN5Ax44=
|
||||
github.com/libp2p/go-libp2p-gostream v0.3.0/go.mod h1:pLBQu8db7vBMNINGsAwLL/ZCE8wng5V1FThoaE5rNjc=
|
||||
github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go=
|
||||
github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8=
|
||||
github.com/libp2p/go-libp2p-http v0.1.5/go.mod h1:2YfPjsQxUlBGFQl2u461unkQ7ukwiSs7NX2eSslOJiU=
|
||||
github.com/libp2p/go-libp2p-http v0.2.0 h1:GYeVd+RZzkRa8XFLITqOpcrIQG6KbFLPJqII6HHBHzY=
|
||||
github.com/libp2p/go-libp2p-http v0.2.0/go.mod h1:GlNKFqDZHe25LVy2CvnZKx75/jLtMaD3VxZV6N39X7E=
|
||||
github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=
|
||||
github.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=
|
||||
github.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=
|
||||
github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k=
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.9.0/go.mod h1:LEKcCFHxnvypOPaqZ0m6h0fLQ9Y8t1iZMOg7a0aQDD4=
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc=
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI=
|
||||
github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70=
|
||||
@ -657,10 +706,12 @@ github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3
|
||||
github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=
|
||||
github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo=
|
||||
github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=
|
||||
github.com/libp2p/go-libp2p-mplex v0.2.4/go.mod h1:mI7iOezdWFOisvUwaYd3IDrJ4oVmgoXK8H331ui39CE=
|
||||
github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs=
|
||||
github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw=
|
||||
github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc=
|
||||
github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g=
|
||||
github.com/libp2p/go-libp2p-nat v0.0.2/go.mod h1:QrjXQSD5Dj4IJOdEcjHRkWTSomyxRo6HnUkf/TfQpLQ=
|
||||
github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY=
|
||||
github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=
|
||||
github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU=
|
||||
@ -684,17 +735,23 @@ github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVd
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ=
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw=
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.4/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.6 h1:2ACefBX23iMdJU9Ke+dcXt3w86MIryes9v7In4+Qq3U=
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
|
||||
github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=
|
||||
github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
|
||||
github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s=
|
||||
github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.2/go.mod h1:Uss7/Cfz872KggNb+doCVPHeCDmXB7z500m/R8DaAUk=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.5/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.4.0/go.mod h1:izkeMLvz6Ht8yAISXjx60XUQZMq9ZMe5h2ih4dLIBIQ=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.4.1 h1:j4umIg5nyus+sqNfU+FWvb9aeYFQH/A+nDFhWj+8yy8=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.4.1/go.mod h1:izkeMLvz6Ht8yAISXjx60XUQZMq9ZMe5h2ih4dLIBIQ=
|
||||
github.com/libp2p/go-libp2p-pubsub-router v0.3.2/go.mod h1:G4MAvYzPxhoR0LEBluS9Ow+Nnr/8iDalUN+RNwVgNkY=
|
||||
github.com/libp2p/go-libp2p-pubsub-router v0.4.0 h1:KjzTLIOBCt0+/4wH6epTxD/Qu4Up/IyeKHlj9MhWRJI=
|
||||
github.com/libp2p/go-libp2p-pubsub-router v0.4.0/go.mod h1:hs0j0ugcBjMOMgJ6diOlZM2rZEId/w5Gg86E+ac4SmQ=
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.8.0/go.mod h1:F2FG/6Bzz0U6essUVxDzE0s9CrY4XGLbl7QEmDNvU7A=
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.10.0 h1:koDCbWD9CCHwcHZL3/WEvP2A+e/o5/W5L3QS/2SPMA0=
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA=
|
||||
github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q=
|
||||
@ -706,15 +763,18 @@ github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ
|
||||
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-secio v0.0.1/go.mod h1:IdG6iQybdcYmbTzxp4J5dwtUEDTOvZrT0opIDVNPrJs=
|
||||
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=
|
||||
github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8=
|
||||
github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY=
|
||||
github.com/libp2p/go-libp2p-swarm v0.0.1/go.mod h1:mh+KZxkbd3lQnveQ3j2q60BM1Cw2mX36XXQqwfPOShs=
|
||||
github.com/libp2p/go-libp2p-swarm v0.0.6/go.mod h1:s5GZvzg9xXe8sbeESuFpjt8CJPTCa8mhEusweJqyFy8=
|
||||
github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4=
|
||||
github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU=
|
||||
github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM=
|
||||
github.com/libp2p/go-libp2p-swarm v0.2.4/go.mod h1:/xIpHFPPh3wmSthtxdGbkHZ0OET1h/GGZes8Wku/M5Y=
|
||||
github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM=
|
||||
github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
|
||||
github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
|
||||
@ -728,13 +788,16 @@ github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MB
|
||||
github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
|
||||
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
|
||||
github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=
|
||||
github.com/libp2p/go-libp2p-testing v0.2.0/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=
|
||||
github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g=
|
||||
github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ=
|
||||
github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0=
|
||||
github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=
|
||||
github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=
|
||||
github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk=
|
||||
github.com/libp2p/go-libp2p-transport v0.0.4/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A=
|
||||
github.com/libp2p/go-libp2p-transport v0.0.5/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A=
|
||||
github.com/libp2p/go-libp2p-transport-upgrader v0.0.1/go.mod h1:NJpUAgQab/8K6K0m+JmZCe5RUXG10UMEx4kWe9Ipj5c=
|
||||
github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc=
|
||||
github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=
|
||||
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=
|
||||
@ -757,6 +820,7 @@ github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9
|
||||
github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
|
||||
github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=
|
||||
github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU=
|
||||
github.com/libp2p/go-mplex v0.0.1/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=
|
||||
github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=
|
||||
github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=
|
||||
github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=
|
||||
@ -765,6 +829,7 @@ github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3
|
||||
github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=
|
||||
github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU=
|
||||
github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=
|
||||
github.com/libp2p/go-msgio v0.0.1/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
||||
github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
||||
github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
||||
github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
||||
@ -786,6 +851,7 @@ github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO
|
||||
github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=
|
||||
github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU=
|
||||
github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=
|
||||
github.com/libp2p/go-reuseport-transport v0.0.1/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=
|
||||
github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=
|
||||
github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM=
|
||||
github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM=
|
||||
@ -800,6 +866,7 @@ github.com/libp2p/go-stream-muxer-multistream v0.1.1/go.mod h1:zmGdfkQ1AzOECIAcc
|
||||
github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc=
|
||||
github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY=
|
||||
github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA=
|
||||
github.com/libp2p/go-tcp-transport v0.0.1/go.mod h1:mnjg0o0O5TmXUaUIanYPUqkW4+u6mK0en8rlpA6BBTs=
|
||||
github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19K427vCzQ+xHKH/o=
|
||||
github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc=
|
||||
github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY=
|
||||
@ -808,6 +875,7 @@ github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KX
|
||||
github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M=
|
||||
github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I=
|
||||
github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc=
|
||||
github.com/libp2p/go-ws-transport v0.0.1/go.mod h1:p3bKjDWHEgtuKKj+2OdPYs5dAPIjtpQGHF2tJfGz7Ww=
|
||||
github.com/libp2p/go-ws-transport v0.0.5/go.mod h1:Qbl4BxPfXXhhd/o0wcrgoaItHqA9tnZjoFZnxykuaXU=
|
||||
github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo=
|
||||
github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM=
|
||||
@ -829,6 +897,7 @@ github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE9
|
||||
github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg=
|
||||
github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4=
|
||||
github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
@ -836,9 +905,11 @@ github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0Q
|
||||
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.0/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc=
|
||||
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.0/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
@ -862,6 +933,7 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1f
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
|
||||
@ -925,10 +997,12 @@ github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysj
|
||||
github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk=
|
||||
github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA=
|
||||
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
|
||||
github.com/multiformats/go-multibase v0.0.2/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
|
||||
github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk=
|
||||
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
|
||||
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.7/go.mod h1:XuKXPp8VHcTygube3OWZC+aZrA+H1IhmjoCDtJc7PXM=
|
||||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
@ -939,6 +1013,7 @@ github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wS
|
||||
github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
|
||||
github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
|
||||
github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38=
|
||||
github.com/multiformats/go-multistream v0.1.2/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k=
|
||||
github.com/multiformats/go-multistream v0.2.0 h1:6AuNmQVKUkRnddw2YiDjt5Elit40SFxMJkVnhmETXtU=
|
||||
github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k=
|
||||
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
@ -1004,6 +1079,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
|
||||
github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
|
||||
github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
|
||||
github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
|
||||
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls=
|
||||
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
@ -1090,6 +1166,7 @@ github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHei
|
||||
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
|
||||
@ -1145,6 +1222,7 @@ github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvS
|
||||
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4=
|
||||
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 h1:bsUlNhdmbtlfdLVXAVfuvKQ01RnWAM09TVrJkI7NZs4=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
|
||||
@ -1155,6 +1233,10 @@ github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h
|
||||
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
|
||||
github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE=
|
||||
github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8=
|
||||
github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible/go.mod h1:34LEDbeKFZInPUrAG+bjuJmUXONGdEFW7XL0SpTY1y4=
|
||||
github.com/whyrusleeping/go-smux-multistream v2.0.2+incompatible/go.mod h1:dRWHHvc4HDQSHh9gbKEBbUZ+f2Q8iZTPG3UOGYODxSQ=
|
||||
github.com/whyrusleeping/go-smux-yamux v2.0.8+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI=
|
||||
github.com/whyrusleeping/go-smux-yamux v2.0.9+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI=
|
||||
github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 h1:ctS9Anw/KozviCCtK6VWMz5kPL9nbQzbQY4yfqlIV4M=
|
||||
github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1/go.mod h1:tKH72zYNt/exx6/5IQO6L9LoQ0rEjd5SbbWaDTs9Zso=
|
||||
github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=
|
||||
@ -1163,10 +1245,12 @@ github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 h1:Y1/FEOpaCpD2
|
||||
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
|
||||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=
|
||||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
|
||||
github.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c/go.mod h1:xxcJeBb7SIUl/Wzkz1eVKJE/CB34YNrqX2TQI6jY9zs=
|
||||
github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b h1:wA3QeTsaAXybLL2kb2cKhCAQTHgYTMwuI8lBlJSv5V8=
|
||||
github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b/go.mod h1:xT1Y5p2JR2PfSZihE0s4mjdJaRGp1waCTf5JzhQLBck=
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow=
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=
|
||||
github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8=
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
@ -1237,6 +1321,7 @@ golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
||||
@ -1261,6 +1346,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
@ -1272,6 +1358,7 @@ 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.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -1327,7 +1414,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -1378,11 +1464,11 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -1438,6 +1524,7 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1-0.20210225150353-54dc8c5edb56 h1:g3QwFWCjsUzBtcQIcI+CYmiL/0i0BxTJjQp54GGDLEM=
|
||||
@ -1523,6 +1610,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
|
||||
@ -1,189 +0,0 @@
|
||||
package keystore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
base32 "encoding/base32"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
)
|
||||
|
||||
var log = logging.Logger("keystore")
|
||||
|
||||
var codec = base32.StdEncoding.WithPadding(base32.NoPadding)
|
||||
|
||||
// Keystore provides a key management interface
|
||||
type Keystore interface {
|
||||
// Has returns whether or not a key exists in the Keystore
|
||||
Has(string) (bool, error)
|
||||
// Put stores a key in the Keystore, if a key with the same name already exists, returns ErrKeyExists
|
||||
Put(string, ci.PrivKey) error
|
||||
// Get retrieves a key from the Keystore if it exists, and returns ErrNoSuchKey
|
||||
// otherwise.
|
||||
Get(string) (ci.PrivKey, error)
|
||||
// Delete removes a key from the Keystore
|
||||
Delete(string) error
|
||||
// List returns a list of key identifier
|
||||
List() ([]string, error)
|
||||
}
|
||||
|
||||
// ErrNoSuchKey is an error message returned when no key of a given name was found.
|
||||
var ErrNoSuchKey = fmt.Errorf("no key by the given name was found")
|
||||
|
||||
// ErrKeyExists is an error message returned when a key already exists
|
||||
var ErrKeyExists = fmt.Errorf("key by that name already exists, refusing to overwrite")
|
||||
|
||||
const keyFilenamePrefix = "key_"
|
||||
|
||||
// FSKeystore is a keystore backed by files in a given directory stored on disk.
|
||||
type FSKeystore struct {
|
||||
dir string
|
||||
}
|
||||
|
||||
// NewFSKeystore returns a new filesystem-backed keystore.
|
||||
func NewFSKeystore(dir string) (*FSKeystore, error) {
|
||||
err := os.Mkdir(dir, 0700)
|
||||
switch {
|
||||
case os.IsExist(err):
|
||||
case err == nil:
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
return &FSKeystore{dir}, nil
|
||||
}
|
||||
|
||||
// Has returns whether or not a key exists in the Keystore
|
||||
func (ks *FSKeystore) Has(name string) (bool, error) {
|
||||
name, err := encode(name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
kp := filepath.Join(ks.dir, name)
|
||||
|
||||
_, err = os.Stat(kp)
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
// Put stores a key in the Keystore, if a key with the same name already exists, returns ErrKeyExists
|
||||
func (ks *FSKeystore) Put(name string, k ci.PrivKey) error {
|
||||
name, err := encode(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := ci.MarshalPrivateKey(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kp := filepath.Join(ks.dir, name)
|
||||
|
||||
fi, err := os.OpenFile(kp, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0400)
|
||||
if err != nil {
|
||||
if os.IsExist(err) {
|
||||
err = ErrKeyExists
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer fi.Close()
|
||||
|
||||
_, err = fi.Write(b)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Get retrieves a key from the Keystore if it exists, and returns ErrNoSuchKey
|
||||
// otherwise.
|
||||
func (ks *FSKeystore) Get(name string) (ci.PrivKey, error) {
|
||||
name, err := encode(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kp := filepath.Join(ks.dir, name)
|
||||
|
||||
data, err := ioutil.ReadFile(kp)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, ErrNoSuchKey
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ci.UnmarshalPrivateKey(data)
|
||||
}
|
||||
|
||||
// Delete removes a key from the Keystore
|
||||
func (ks *FSKeystore) Delete(name string) error {
|
||||
name, err := encode(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kp := filepath.Join(ks.dir, name)
|
||||
|
||||
return os.Remove(kp)
|
||||
}
|
||||
|
||||
// List return a list of key identifier
|
||||
func (ks *FSKeystore) List() ([]string, error) {
|
||||
dir, err := os.Open(ks.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dirs, err := dir.Readdirnames(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := make([]string, 0, len(dirs))
|
||||
|
||||
for _, name := range dirs {
|
||||
decodedName, err := decode(name)
|
||||
if err == nil {
|
||||
list = append(list, decodedName)
|
||||
} else {
|
||||
log.Errorf("Ignoring keyfile with invalid encoded filename: %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func encode(name string) (string, error) {
|
||||
if name == "" {
|
||||
return "", fmt.Errorf("key name must be at least one character")
|
||||
}
|
||||
|
||||
encodedName := codec.EncodeToString([]byte(name))
|
||||
log.Debugf("Encoded key name: %s to: %s", name, encodedName)
|
||||
|
||||
return keyFilenamePrefix + strings.ToLower(encodedName), nil
|
||||
}
|
||||
|
||||
func decode(name string) (string, error) {
|
||||
if !strings.HasPrefix(name, keyFilenamePrefix) {
|
||||
return "", fmt.Errorf("key's filename has unexpected format")
|
||||
}
|
||||
|
||||
nameWithoutPrefix := strings.ToUpper(name[len(keyFilenamePrefix):])
|
||||
decodedName, err := codec.DecodeString(nameWithoutPrefix)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
log.Debugf("Decoded key name: %s to: %s", name, decodedName)
|
||||
|
||||
return string(decodedName), nil
|
||||
}
|
||||
@ -1,278 +0,0 @@
|
||||
package keystore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
)
|
||||
|
||||
type rr struct{}
|
||||
|
||||
func (rr rr) Read(b []byte) (int, error) {
|
||||
return rand.Read(b)
|
||||
}
|
||||
|
||||
func privKeyOrFatal(t *testing.T) ci.PrivKey {
|
||||
priv, _, err := ci.GenerateEd25519Key(rr{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return priv
|
||||
}
|
||||
|
||||
func TestKeystoreBasics(t *testing.T) {
|
||||
tdir, err := ioutil.TempDir("", "keystore-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ks, err := NewFSKeystore(tdir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err := ks.List()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(l) != 0 {
|
||||
t.Fatal("expected no keys")
|
||||
}
|
||||
|
||||
k1 := privKeyOrFatal(t)
|
||||
k2 := privKeyOrFatal(t)
|
||||
k3 := privKeyOrFatal(t)
|
||||
k4 := privKeyOrFatal(t)
|
||||
|
||||
err = ks.Put("foo", k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ks.Put("bar", k2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err = ks.List()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sort.Strings(l)
|
||||
if l[0] != "bar" || l[1] != "foo" {
|
||||
t.Fatal("wrong entries listed")
|
||||
}
|
||||
|
||||
if err := assertDirContents(tdir, []string{"foo", "bar"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ks.Put("foo", k3)
|
||||
if err == nil {
|
||||
t.Fatal("should not be able to overwrite key")
|
||||
}
|
||||
|
||||
if err := assertDirContents(tdir, []string{"foo", "bar"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
exist, err := ks.Has("foo")
|
||||
if !exist {
|
||||
t.Fatal("should know it has a key named foo")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
exist, err = ks.Has("nonexistingkey")
|
||||
if exist {
|
||||
t.Fatal("should know it doesn't have a key named nonexistingkey")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ks.Delete("bar"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := assertDirContents(tdir, []string{"foo"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ks.Put("beep", k3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ks.Put("boop", k4); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := assertDirContents(tdir, []string{"foo", "beep", "boop"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := assertGetKey(ks, "foo", k1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := assertGetKey(ks, "beep", k3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := assertGetKey(ks, "boop", k4); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ks.Put("..///foo/", k1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ks.Put("", k1); err == nil {
|
||||
t.Fatal("shouldn't be able to put a key with no name")
|
||||
}
|
||||
|
||||
if err := ks.Put(".foo", k1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidKeyFiles(t *testing.T) {
|
||||
tdir, err := ioutil.TempDir("", "keystore-test")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer os.RemoveAll(tdir)
|
||||
|
||||
ks, err := NewFSKeystore(tdir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
key := privKeyOrFatal(t)
|
||||
|
||||
bytes, err := key.Bytes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
encodedName, err := encode("valid")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(ks.dir, encodedName), bytes, 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(ks.dir, "z.invalid"), bytes, 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err := ks.List()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sort.Strings(l)
|
||||
if len(l) != 1 {
|
||||
t.Fatal("wrong entry count")
|
||||
}
|
||||
|
||||
if l[0] != "valid" {
|
||||
t.Fatal("wrong entries listed")
|
||||
}
|
||||
|
||||
exist, err := ks.Has("valid")
|
||||
if !exist {
|
||||
t.Fatal("should know it has a key named valid")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonExistingKey(t *testing.T) {
|
||||
tdir, err := ioutil.TempDir("", "keystore-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ks, err := NewFSKeystore(tdir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
k, err := ks.Get("does-it-exist")
|
||||
if err != ErrNoSuchKey {
|
||||
t.Fatalf("expected: %s, got %s", ErrNoSuchKey, err)
|
||||
}
|
||||
if k != nil {
|
||||
t.Fatalf("Get on nonexistant key should give nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeKeystoreNoDir(t *testing.T) {
|
||||
_, err := NewFSKeystore("/this/is/not/a/real/dir")
|
||||
if err == nil {
|
||||
t.Fatal("shouldnt be able to make a keystore in a nonexistant directory")
|
||||
}
|
||||
}
|
||||
|
||||
func assertGetKey(ks Keystore, name string, exp ci.PrivKey) error {
|
||||
outK, err := ks.Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !outK.Equals(exp) {
|
||||
return fmt.Errorf("key we got out didn't match expectation")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func assertDirContents(dir string, exp []string) error {
|
||||
finfos, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(finfos) != len(exp) {
|
||||
return fmt.Errorf("expected %d directory entries", len(exp))
|
||||
}
|
||||
|
||||
var names []string
|
||||
for _, fi := range finfos {
|
||||
decodedName, err := decode(fi.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
names = append(names, decodedName)
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
sort.Strings(exp)
|
||||
if len(names) != len(exp) {
|
||||
return fmt.Errorf("directory had wrong number of entries in it")
|
||||
}
|
||||
|
||||
for i, v := range names {
|
||||
if v != exp[i] {
|
||||
return fmt.Errorf("had wrong entry in directory")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
package keystore
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
)
|
||||
|
||||
// MemKeystore is an in memory keystore implementation that is not persisted to
|
||||
// any backing storage.
|
||||
type MemKeystore struct {
|
||||
keys map[string]ci.PrivKey
|
||||
}
|
||||
|
||||
// NewMemKeystore creates a MemKeystore.
|
||||
func NewMemKeystore() *MemKeystore {
|
||||
return &MemKeystore{make(map[string]ci.PrivKey)}
|
||||
}
|
||||
|
||||
// Has return whether or not a key exists in the Keystore
|
||||
func (mk *MemKeystore) Has(name string) (bool, error) {
|
||||
_, ok := mk.keys[name]
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
// Put store a key in the Keystore
|
||||
func (mk *MemKeystore) Put(name string, k ci.PrivKey) error {
|
||||
if name == "" {
|
||||
return errors.New("key name must be at least one character")
|
||||
}
|
||||
|
||||
_, ok := mk.keys[name]
|
||||
if ok {
|
||||
return ErrKeyExists
|
||||
}
|
||||
|
||||
mk.keys[name] = k
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get retrieve a key from the Keystore
|
||||
func (mk *MemKeystore) Get(name string) (ci.PrivKey, error) {
|
||||
k, ok := mk.keys[name]
|
||||
if !ok {
|
||||
return nil, ErrNoSuchKey
|
||||
}
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// Delete remove a key from the Keystore
|
||||
func (mk *MemKeystore) Delete(name string) error {
|
||||
delete(mk.keys, name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// List return a list of key identifier
|
||||
func (mk *MemKeystore) List() ([]string, error) {
|
||||
out := make([]string, 0, len(mk.keys))
|
||||
for k := range mk.keys {
|
||||
out = append(out, k)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
@ -1,99 +0,0 @@
|
||||
package keystore
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMemKeyStoreBasics(t *testing.T) {
|
||||
ks := NewMemKeystore()
|
||||
|
||||
l, err := ks.List()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(l) != 0 {
|
||||
t.Fatal("expected no keys")
|
||||
}
|
||||
|
||||
k1 := privKeyOrFatal(t)
|
||||
k2 := privKeyOrFatal(t)
|
||||
k3 := privKeyOrFatal(t)
|
||||
k4 := privKeyOrFatal(t)
|
||||
|
||||
err = ks.Put("foo", k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ks.Put("bar", k2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err = ks.List()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sort.Strings(l)
|
||||
if l[0] != "bar" || l[1] != "foo" {
|
||||
t.Fatal("wrong entries listed")
|
||||
}
|
||||
|
||||
err = ks.Put("foo", k3)
|
||||
if err == nil {
|
||||
t.Fatal("should not be able to overwrite key")
|
||||
}
|
||||
|
||||
exist, err := ks.Has("foo")
|
||||
if !exist {
|
||||
t.Fatal("should know it has a key named foo")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
exist, err = ks.Has("nonexistingkey")
|
||||
if exist {
|
||||
t.Fatal("should know it doesn't have a key named nonexistingkey")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ks.Delete("bar"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ks.Put("beep", k3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ks.Put("boop", k4); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := assertGetKey(ks, "foo", k1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := assertGetKey(ks, "beep", k3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := assertGetKey(ks, "boop", k4); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ks.Put("..///foo/", k1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ks.Put("", k1); err == nil {
|
||||
t.Fatal("shouldn't be able to put a key with no name")
|
||||
}
|
||||
|
||||
if err := ks.Put(".foo", k1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
120
namesys/base.go
120
namesys/base.go
@ -1,120 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
path "github.com/ipfs/go-path"
|
||||
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
|
||||
)
|
||||
|
||||
type onceResult struct {
|
||||
value path.Path
|
||||
ttl time.Duration
|
||||
err error
|
||||
}
|
||||
|
||||
type resolver interface {
|
||||
resolveOnceAsync(ctx context.Context, name string, options opts.ResolveOpts) <-chan onceResult
|
||||
}
|
||||
|
||||
// resolve is a helper for implementing Resolver.ResolveN using resolveOnce.
|
||||
func resolve(ctx context.Context, r resolver, name string, options opts.ResolveOpts) (path.Path, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
err := ErrResolveFailed
|
||||
var p path.Path
|
||||
|
||||
resCh := resolveAsync(ctx, r, name, options)
|
||||
|
||||
for res := range resCh {
|
||||
p, err = res.Path, res.Err
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return p, err
|
||||
}
|
||||
|
||||
func resolveAsync(ctx context.Context, r resolver, name string, options opts.ResolveOpts) <-chan Result {
|
||||
resCh := r.resolveOnceAsync(ctx, name, options)
|
||||
depth := options.Depth
|
||||
outCh := make(chan Result, 1)
|
||||
|
||||
go func() {
|
||||
defer close(outCh)
|
||||
var subCh <-chan Result
|
||||
var cancelSub context.CancelFunc
|
||||
defer func() {
|
||||
if cancelSub != nil {
|
||||
cancelSub()
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case res, ok := <-resCh:
|
||||
if !ok {
|
||||
resCh = nil
|
||||
break
|
||||
}
|
||||
|
||||
if res.err != nil {
|
||||
emitResult(ctx, outCh, Result{Err: res.err})
|
||||
return
|
||||
}
|
||||
log.Debugf("resolved %s to %s", name, res.value.String())
|
||||
if !strings.HasPrefix(res.value.String(), ipnsPrefix) {
|
||||
emitResult(ctx, outCh, Result{Path: res.value})
|
||||
break
|
||||
}
|
||||
|
||||
if depth == 1 {
|
||||
emitResult(ctx, outCh, Result{Path: res.value, Err: ErrResolveRecursion})
|
||||
break
|
||||
}
|
||||
|
||||
subopts := options
|
||||
if subopts.Depth > 1 {
|
||||
subopts.Depth--
|
||||
}
|
||||
|
||||
var subCtx context.Context
|
||||
if cancelSub != nil {
|
||||
// Cancel previous recursive resolve since it won't be used anyways
|
||||
cancelSub()
|
||||
}
|
||||
subCtx, cancelSub = context.WithCancel(ctx)
|
||||
_ = cancelSub
|
||||
|
||||
p := strings.TrimPrefix(res.value.String(), ipnsPrefix)
|
||||
subCh = resolveAsync(subCtx, r, p, subopts)
|
||||
case res, ok := <-subCh:
|
||||
if !ok {
|
||||
subCh = nil
|
||||
break
|
||||
}
|
||||
|
||||
// We don't bother returning here in case of context timeout as there is
|
||||
// no good reason to do that, and we may still be able to emit a result
|
||||
emitResult(ctx, outCh, res)
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
if resCh == nil && subCh == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return outCh
|
||||
}
|
||||
|
||||
func emitResult(ctx context.Context, outCh chan<- Result, r Result) {
|
||||
select {
|
||||
case outCh <- r:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
path "github.com/ipfs/go-path"
|
||||
)
|
||||
|
||||
func (ns *mpns) cacheGet(name string) (path.Path, bool) {
|
||||
// existence of optional mapping defined via IPFS_NS_MAP is checked first
|
||||
if ns.staticMap != nil {
|
||||
val, ok := ns.staticMap[name]
|
||||
if ok {
|
||||
return val, true
|
||||
}
|
||||
}
|
||||
|
||||
if ns.cache == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
ientry, ok := ns.cache.Get(name)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
entry, ok := ientry.(cacheEntry)
|
||||
if !ok {
|
||||
// should never happen, purely for sanity
|
||||
log.Panicf("unexpected type %T in cache for %q.", ientry, name)
|
||||
}
|
||||
|
||||
if time.Now().Before(entry.eol) {
|
||||
return entry.val, true
|
||||
}
|
||||
|
||||
ns.cache.Remove(name)
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (ns *mpns) cacheSet(name string, val path.Path, ttl time.Duration) {
|
||||
if ns.cache == nil || ttl <= 0 {
|
||||
return
|
||||
}
|
||||
ns.cache.Add(name, cacheEntry{
|
||||
val: val,
|
||||
eol: time.Now().Add(ttl),
|
||||
})
|
||||
}
|
||||
|
||||
func (ns *mpns) cacheInvalidate(name string) {
|
||||
if ns.cache == nil {
|
||||
return
|
||||
}
|
||||
ns.cache.Remove(name)
|
||||
}
|
||||
|
||||
type cacheEntry struct {
|
||||
val path.Path
|
||||
eol time.Time
|
||||
}
|
||||
159
namesys/dns.go
159
namesys/dns.go
@ -1,159 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
path "github.com/ipfs/go-path"
|
||||
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
|
||||
isd "github.com/jbenet/go-is-domain"
|
||||
)
|
||||
|
||||
const ethTLD = "eth"
|
||||
const linkTLD = "link"
|
||||
|
||||
type LookupTXTFunc func(name string) (txt []string, err error)
|
||||
|
||||
// DNSResolver implements a Resolver on DNS domains
|
||||
type DNSResolver struct {
|
||||
lookupTXT LookupTXTFunc
|
||||
// TODO: maybe some sort of caching?
|
||||
// cache would need a timeout
|
||||
}
|
||||
|
||||
// NewDNSResolver constructs a name resolver using DNS TXT records.
|
||||
func NewDNSResolver() *DNSResolver {
|
||||
return &DNSResolver{lookupTXT: net.LookupTXT}
|
||||
}
|
||||
|
||||
// Resolve implements Resolver.
|
||||
func (r *DNSResolver) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) {
|
||||
return resolve(ctx, r, name, opts.ProcessOpts(options))
|
||||
}
|
||||
|
||||
// ResolveAsync implements Resolver.
|
||||
func (r *DNSResolver) ResolveAsync(ctx context.Context, name string, options ...opts.ResolveOpt) <-chan Result {
|
||||
return resolveAsync(ctx, r, name, opts.ProcessOpts(options))
|
||||
}
|
||||
|
||||
type lookupRes struct {
|
||||
path path.Path
|
||||
error error
|
||||
}
|
||||
|
||||
// resolveOnce implements resolver.
|
||||
// TXT records for a given domain name should contain a b58
|
||||
// encoded multihash.
|
||||
func (r *DNSResolver) resolveOnceAsync(ctx context.Context, name string, options opts.ResolveOpts) <-chan onceResult {
|
||||
var fqdn string
|
||||
out := make(chan onceResult, 1)
|
||||
segments := strings.SplitN(name, "/", 2)
|
||||
domain := segments[0]
|
||||
|
||||
if !isd.IsDomain(domain) {
|
||||
out <- onceResult{err: fmt.Errorf("not a valid domain name: %s", domain)}
|
||||
close(out)
|
||||
return out
|
||||
}
|
||||
log.Debugf("DNSResolver resolving %s", domain)
|
||||
|
||||
if strings.HasSuffix(domain, ".") {
|
||||
fqdn = domain
|
||||
} else {
|
||||
fqdn = domain + "."
|
||||
}
|
||||
|
||||
if strings.HasSuffix(fqdn, "."+ethTLD+".") {
|
||||
// This is an ENS name. As we're resolving via an arbitrary DNS server
|
||||
// that may not know about .eth we need to add our link domain suffix.
|
||||
fqdn += linkTLD + "."
|
||||
}
|
||||
|
||||
rootChan := make(chan lookupRes, 1)
|
||||
go workDomain(r, fqdn, rootChan)
|
||||
|
||||
subChan := make(chan lookupRes, 1)
|
||||
go workDomain(r, "_dnslink."+fqdn, subChan)
|
||||
|
||||
appendPath := func(p path.Path) (path.Path, error) {
|
||||
if len(segments) > 1 {
|
||||
return path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[1])
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(out)
|
||||
for {
|
||||
select {
|
||||
case subRes, ok := <-subChan:
|
||||
if !ok {
|
||||
subChan = nil
|
||||
break
|
||||
}
|
||||
if subRes.error == nil {
|
||||
p, err := appendPath(subRes.path)
|
||||
emitOnceResult(ctx, out, onceResult{value: p, err: err})
|
||||
return
|
||||
}
|
||||
case rootRes, ok := <-rootChan:
|
||||
if !ok {
|
||||
rootChan = nil
|
||||
break
|
||||
}
|
||||
if rootRes.error == nil {
|
||||
p, err := appendPath(rootRes.path)
|
||||
emitOnceResult(ctx, out, onceResult{value: p, err: err})
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
if subChan == nil && rootChan == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func workDomain(r *DNSResolver, name string, res chan lookupRes) {
|
||||
defer close(res)
|
||||
|
||||
txt, err := r.lookupTXT(name)
|
||||
if err != nil {
|
||||
// Error is != nil
|
||||
res <- lookupRes{"", err}
|
||||
return
|
||||
}
|
||||
|
||||
for _, t := range txt {
|
||||
p, err := parseEntry(t)
|
||||
if err == nil {
|
||||
res <- lookupRes{p, nil}
|
||||
return
|
||||
}
|
||||
}
|
||||
res <- lookupRes{"", ErrResolveFailed}
|
||||
}
|
||||
|
||||
func parseEntry(txt string) (path.Path, error) {
|
||||
p, err := path.ParseCidToPath(txt) // bare IPFS multihashes
|
||||
if err == nil {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
return tryParseDnsLink(txt)
|
||||
}
|
||||
|
||||
func tryParseDnsLink(txt string) (path.Path, error) {
|
||||
parts := strings.SplitN(txt, "=", 2)
|
||||
if len(parts) == 2 && parts[0] == "dnslink" {
|
||||
return path.ParsePath(parts[1])
|
||||
}
|
||||
|
||||
return "", errors.New("not a valid dnslink entry")
|
||||
}
|
||||
@ -1,172 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
|
||||
)
|
||||
|
||||
type mockDNS struct {
|
||||
entries map[string][]string
|
||||
}
|
||||
|
||||
func (m *mockDNS) lookupTXT(name string) (txt []string, err error) {
|
||||
txt, ok := m.entries[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no TXT entry for %s", name)
|
||||
}
|
||||
return txt, nil
|
||||
}
|
||||
|
||||
func TestDnsEntryParsing(t *testing.T) {
|
||||
|
||||
goodEntries := []string{
|
||||
"QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
"dnslink=/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/foo",
|
||||
"dnslink=/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/bar",
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/foo/bar/baz",
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/foo/bar/baz/",
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
}
|
||||
|
||||
badEntries := []string{
|
||||
"QmYhE8xgFCjGcz6PHgnvJz5NOTCORRECT",
|
||||
"quux=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
"dnslink=",
|
||||
"dnslink=/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/foo",
|
||||
"dnslink=ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/bar",
|
||||
}
|
||||
|
||||
for _, e := range goodEntries {
|
||||
_, err := parseEntry(e)
|
||||
if err != nil {
|
||||
t.Log("expected entry to parse correctly!")
|
||||
t.Log(e)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, e := range badEntries {
|
||||
_, err := parseEntry(e)
|
||||
if err == nil {
|
||||
t.Log("expected entry parse to fail!")
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newMockDNS() *mockDNS {
|
||||
return &mockDNS{
|
||||
entries: map[string][]string{
|
||||
"multihash.example.com.": {
|
||||
"dnslink=QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
},
|
||||
"ipfs.example.com.": {
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
},
|
||||
"_dnslink.dipfs.example.com.": {
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
},
|
||||
"dns1.example.com.": {
|
||||
"dnslink=/ipns/ipfs.example.com",
|
||||
},
|
||||
"dns2.example.com.": {
|
||||
"dnslink=/ipns/dns1.example.com",
|
||||
},
|
||||
"multi.example.com.": {
|
||||
"some stuff",
|
||||
"dnslink=/ipns/dns1.example.com",
|
||||
"masked dnslink=/ipns/example.invalid",
|
||||
},
|
||||
"equals.example.com.": {
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/=equals",
|
||||
},
|
||||
"loop1.example.com.": {
|
||||
"dnslink=/ipns/loop2.example.com",
|
||||
},
|
||||
"loop2.example.com.": {
|
||||
"dnslink=/ipns/loop1.example.com",
|
||||
},
|
||||
"_dnslink.dloop1.example.com.": {
|
||||
"dnslink=/ipns/loop2.example.com",
|
||||
},
|
||||
"_dnslink.dloop2.example.com.": {
|
||||
"dnslink=/ipns/loop1.example.com",
|
||||
},
|
||||
"bad.example.com.": {
|
||||
"dnslink=",
|
||||
},
|
||||
"withsegment.example.com.": {
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment",
|
||||
},
|
||||
"withrecsegment.example.com.": {
|
||||
"dnslink=/ipns/withsegment.example.com/subsub",
|
||||
},
|
||||
"withtrailing.example.com.": {
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/",
|
||||
},
|
||||
"withtrailingrec.example.com.": {
|
||||
"dnslink=/ipns/withtrailing.example.com/segment/",
|
||||
},
|
||||
"double.example.com.": {
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
},
|
||||
"_dnslink.double.example.com.": {
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
},
|
||||
"double.conflict.com.": {
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
|
||||
},
|
||||
"_dnslink.conflict.example.com.": {
|
||||
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjE",
|
||||
},
|
||||
"fqdn.example.com.": {
|
||||
"dnslink=/ipfs/QmYvMB9yrsSf7RKBghkfwmHJkzJhW2ZgVwq3LxBXXPasFr",
|
||||
},
|
||||
"www.wealdtech.eth.link.": {
|
||||
"dnslink=/ipns/ipfs.example.com",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSResolution(t *testing.T) {
|
||||
mock := newMockDNS()
|
||||
r := &DNSResolver{lookupTXT: mock.lookupTXT}
|
||||
testResolution(t, r, "multihash.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
|
||||
testResolution(t, r, "ipfs.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
|
||||
testResolution(t, r, "dipfs.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
|
||||
testResolution(t, r, "dns1.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
|
||||
testResolution(t, r, "dns1.example.com", 1, "/ipns/ipfs.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "dns2.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
|
||||
testResolution(t, r, "dns2.example.com", 1, "/ipns/dns1.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "dns2.example.com", 2, "/ipns/ipfs.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "multi.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
|
||||
testResolution(t, r, "multi.example.com", 1, "/ipns/dns1.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "multi.example.com", 2, "/ipns/ipfs.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "equals.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/=equals", nil)
|
||||
testResolution(t, r, "loop1.example.com", 1, "/ipns/loop2.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "loop1.example.com", 2, "/ipns/loop1.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "loop1.example.com", 3, "/ipns/loop2.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "loop1.example.com", opts.DefaultDepthLimit, "/ipns/loop1.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "dloop1.example.com", 1, "/ipns/loop2.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "dloop1.example.com", 2, "/ipns/loop1.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "dloop1.example.com", 3, "/ipns/loop2.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "dloop1.example.com", opts.DefaultDepthLimit, "/ipns/loop1.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "bad.example.com", opts.DefaultDepthLimit, "", ErrResolveFailed)
|
||||
testResolution(t, r, "withsegment.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment", nil)
|
||||
testResolution(t, r, "withrecsegment.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub", nil)
|
||||
testResolution(t, r, "withsegment.example.com/test1", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/test1", nil)
|
||||
testResolution(t, r, "withrecsegment.example.com/test2", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub/test2", nil)
|
||||
testResolution(t, r, "withrecsegment.example.com/test3/", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub/test3/", nil)
|
||||
testResolution(t, r, "withtrailingrec.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/", nil)
|
||||
testResolution(t, r, "double.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
|
||||
testResolution(t, r, "conflict.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjE", nil)
|
||||
testResolution(t, r, "fqdn.example.com.", opts.DefaultDepthLimit, "/ipfs/QmYvMB9yrsSf7RKBghkfwmHJkzJhW2ZgVwq3LxBXXPasFr", nil)
|
||||
testResolution(t, r, "www.wealdtech.eth", 1, "/ipns/ipfs.example.com", ErrResolveRecursion)
|
||||
testResolution(t, r, "www.wealdtech.eth", 2, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
|
||||
testResolution(t, r, "www.wealdtech.eth.link", 2, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
|
||||
}
|
||||
@ -1,106 +0,0 @@
|
||||
/*
|
||||
Package namesys implements resolvers and publishers for the IPFS
|
||||
naming system (IPNS).
|
||||
|
||||
The core of IPFS is an immutable, content-addressable Merkle graph.
|
||||
That works well for many use cases, but doesn't allow you to answer
|
||||
questions like "what is Alice's current homepage?". The mutable name
|
||||
system allows Alice to publish information like:
|
||||
|
||||
The current homepage for alice.example.com is
|
||||
/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
|
||||
|
||||
or:
|
||||
|
||||
The current homepage for node
|
||||
QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
|
||||
is
|
||||
/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
|
||||
|
||||
The mutable name system also allows users to resolve those references
|
||||
to find the immutable IPFS object currently referenced by a given
|
||||
mutable name.
|
||||
|
||||
For command-line bindings to this functionality, see:
|
||||
|
||||
ipfs name
|
||||
ipfs dns
|
||||
ipfs resolve
|
||||
*/
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
context "context"
|
||||
|
||||
path "github.com/ipfs/go-path"
|
||||
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
)
|
||||
|
||||
// ErrResolveFailed signals an error when attempting to resolve.
|
||||
var ErrResolveFailed = errors.New("could not resolve name")
|
||||
|
||||
// ErrResolveRecursion signals a recursion-depth limit.
|
||||
var ErrResolveRecursion = errors.New(
|
||||
"could not resolve name (recursion limit exceeded)")
|
||||
|
||||
// ErrPublishFailed signals an error when attempting to publish.
|
||||
var ErrPublishFailed = errors.New("could not publish name")
|
||||
|
||||
// Namesys represents a cohesive name publishing and resolving system.
|
||||
//
|
||||
// Publishing a name is the process of establishing a mapping, a key-value
|
||||
// pair, according to naming rules and databases.
|
||||
//
|
||||
// Resolving a name is the process of looking up the value associated with the
|
||||
// key (name).
|
||||
type NameSystem interface {
|
||||
Resolver
|
||||
Publisher
|
||||
}
|
||||
|
||||
// Result is the return type for Resolver.ResolveAsync.
|
||||
type Result struct {
|
||||
Path path.Path
|
||||
Err error
|
||||
}
|
||||
|
||||
// Resolver is an object capable of resolving names.
|
||||
type Resolver interface {
|
||||
|
||||
// Resolve performs a recursive lookup, returning the dereferenced
|
||||
// path. For example, if ipfs.io has a DNS TXT record pointing to
|
||||
// /ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
|
||||
// and there is a DHT IPNS entry for
|
||||
// QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
|
||||
// -> /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
|
||||
// then
|
||||
// Resolve(ctx, "/ipns/ipfs.io")
|
||||
// will resolve both names, returning
|
||||
// /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
|
||||
//
|
||||
// There is a default depth-limit to avoid infinite recursion. Most
|
||||
// users will be fine with this default limit, but if you need to
|
||||
// adjust the limit you can specify it as an option.
|
||||
Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (value path.Path, err error)
|
||||
|
||||
// ResolveAsync performs recursive name lookup, like Resolve, but it returns
|
||||
// entries as they are discovered in the DHT. Each returned result is guaranteed
|
||||
// to be "better" (which usually means newer) than the previous one.
|
||||
ResolveAsync(ctx context.Context, name string, options ...opts.ResolveOpt) <-chan Result
|
||||
}
|
||||
|
||||
// Publisher is an object capable of publishing particular names.
|
||||
type Publisher interface {
|
||||
|
||||
// Publish establishes a name-value mapping.
|
||||
// TODO make this not PrivKey specific.
|
||||
Publish(ctx context.Context, name ci.PrivKey, value path.Path) error
|
||||
|
||||
// TODO: to be replaced by a more generic 'PublishWithValidity' type
|
||||
// call once the records spec is implemented
|
||||
PublishWithEOL(ctx context.Context, name ci.PrivKey, value path.Path, eol time.Time) error
|
||||
}
|
||||
@ -1,206 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
dssync "github.com/ipfs/go-datastore/sync"
|
||||
mockrouting "github.com/ipfs/go-ipfs-routing/mock"
|
||||
offline "github.com/ipfs/go-ipfs-routing/offline"
|
||||
ipns "github.com/ipfs/go-ipns"
|
||||
ipns_pb "github.com/ipfs/go-ipns/pb"
|
||||
path "github.com/ipfs/go-path"
|
||||
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
pstore "github.com/libp2p/go-libp2p-core/peerstore"
|
||||
routing "github.com/libp2p/go-libp2p-core/routing"
|
||||
"github.com/libp2p/go-libp2p-core/test"
|
||||
pstoremem "github.com/libp2p/go-libp2p-peerstore/pstoremem"
|
||||
record "github.com/libp2p/go-libp2p-record"
|
||||
testutil "github.com/libp2p/go-libp2p-testing/net"
|
||||
)
|
||||
|
||||
func TestResolverValidation(t *testing.T) {
|
||||
t.Run("RSA",
|
||||
func(t *testing.T) {
|
||||
testResolverValidation(t, ci.RSA)
|
||||
})
|
||||
t.Run("Ed25519",
|
||||
func(t *testing.T) {
|
||||
testResolverValidation(t, ci.Ed25519)
|
||||
})
|
||||
t.Run("ECDSA",
|
||||
func(t *testing.T) {
|
||||
testResolverValidation(t, ci.ECDSA)
|
||||
})
|
||||
t.Run("Secp256k1",
|
||||
func(t *testing.T) {
|
||||
testResolverValidation(t, ci.Secp256k1)
|
||||
})
|
||||
}
|
||||
|
||||
func testResolverValidation(t *testing.T, keyType int) {
|
||||
ctx := context.Background()
|
||||
rid := testutil.RandIdentityOrFatal(t)
|
||||
dstore := dssync.MutexWrap(ds.NewMapDatastore())
|
||||
peerstore := pstoremem.NewPeerstore()
|
||||
|
||||
vstore := newMockValueStore(rid, dstore, peerstore)
|
||||
resolver := NewIpnsResolver(vstore)
|
||||
|
||||
nvVstore := offline.NewOfflineRouter(dstore, mockrouting.MockValidator{})
|
||||
|
||||
// Create entry with expiry in one hour
|
||||
priv, id, _, ipnsDHTPath := genKeys(t, keyType)
|
||||
ts := time.Now()
|
||||
p := []byte("/ipfs/QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG")
|
||||
entry, err := createIPNSRecordWithEmbeddedPublicKey(priv, p, 1, ts.Add(time.Hour))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Publish entry
|
||||
err = PublishEntry(ctx, vstore, ipnsDHTPath, entry)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Resolve entry
|
||||
resp, err := resolve(ctx, resolver, id.Pretty(), opts.DefaultResolveOpts())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp != path.Path(p) {
|
||||
t.Fatalf("Mismatch between published path %s and resolved path %s", p, resp)
|
||||
}
|
||||
// Create expired entry
|
||||
expiredEntry, err := createIPNSRecordWithEmbeddedPublicKey(priv, p, 1, ts.Add(-1*time.Hour))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Publish entry
|
||||
err = PublishEntry(ctx, nvVstore, ipnsDHTPath, expiredEntry)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Record should fail validation because entry is expired
|
||||
_, err = resolve(ctx, resolver, id.Pretty(), opts.DefaultResolveOpts())
|
||||
if err == nil {
|
||||
t.Fatal("ValidateIpnsRecord should have returned error")
|
||||
}
|
||||
|
||||
// Create IPNS record path with a different private key
|
||||
priv2, id2, _, ipnsDHTPath2 := genKeys(t, keyType)
|
||||
|
||||
// Publish entry
|
||||
err = PublishEntry(ctx, nvVstore, ipnsDHTPath2, entry)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Record should fail validation because public key defined by
|
||||
// ipns path doesn't match record signature
|
||||
_, err = resolve(ctx, resolver, id2.Pretty(), opts.DefaultResolveOpts())
|
||||
if err == nil {
|
||||
t.Fatal("ValidateIpnsRecord should have failed signature verification")
|
||||
}
|
||||
|
||||
// Try embedding the incorrect private key inside the entry
|
||||
if err := ipns.EmbedPublicKey(priv2.GetPublic(), entry); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Publish entry
|
||||
err = PublishEntry(ctx, nvVstore, ipnsDHTPath2, entry)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Record should fail validation because public key defined by
|
||||
// ipns path doesn't match record signature
|
||||
_, err = resolve(ctx, resolver, id2.Pretty(), opts.DefaultResolveOpts())
|
||||
if err == nil {
|
||||
t.Fatal("ValidateIpnsRecord should have failed signature verification")
|
||||
}
|
||||
}
|
||||
|
||||
func genKeys(t *testing.T, keyType int) (ci.PrivKey, peer.ID, string, string) {
|
||||
bits := 0
|
||||
if keyType == ci.RSA {
|
||||
bits = 2048
|
||||
}
|
||||
|
||||
sk, pk, err := test.RandTestKeyPair(keyType, bits)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
id, err := peer.IDFromPublicKey(pk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return sk, id, PkKeyForID(id), ipns.RecordKey(id)
|
||||
}
|
||||
|
||||
func createIPNSRecordWithEmbeddedPublicKey(sk ci.PrivKey, val []byte, seq uint64, eol time.Time) (*ipns_pb.IpnsEntry, error) {
|
||||
entry, err := ipns.Create(sk, val, seq, eol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ipns.EmbedPublicKey(sk.GetPublic(), entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return entry, nil
|
||||
}
|
||||
|
||||
type mockValueStore struct {
|
||||
r routing.ValueStore
|
||||
kbook pstore.KeyBook
|
||||
}
|
||||
|
||||
func newMockValueStore(id testutil.Identity, dstore ds.Datastore, kbook pstore.KeyBook) *mockValueStore {
|
||||
return &mockValueStore{
|
||||
r: offline.NewOfflineRouter(dstore, record.NamespacedValidator{
|
||||
"ipns": ipns.Validator{KeyBook: kbook},
|
||||
"pk": record.PublicKeyValidator{},
|
||||
}),
|
||||
kbook: kbook,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockValueStore) GetValue(ctx context.Context, k string, opts ...routing.Option) ([]byte, error) {
|
||||
return m.r.GetValue(ctx, k, opts...)
|
||||
}
|
||||
|
||||
func (m *mockValueStore) SearchValue(ctx context.Context, k string, opts ...routing.Option) (<-chan []byte, error) {
|
||||
return m.r.SearchValue(ctx, k, opts...)
|
||||
}
|
||||
|
||||
func (m *mockValueStore) GetPublicKey(ctx context.Context, p peer.ID) (ci.PubKey, error) {
|
||||
pk := m.kbook.PubKey(p)
|
||||
if pk != nil {
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
pkkey := routing.KeyForPublicKey(p)
|
||||
val, err := m.GetValue(ctx, pkkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk, err = ci.UnmarshalPublicKey(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pk, m.kbook.AddPubKey(p, pk)
|
||||
}
|
||||
|
||||
func (m *mockValueStore) PutValue(ctx context.Context, k string, d []byte, opts ...routing.Option) error {
|
||||
return m.r.PutValue(ctx, k, d, opts...)
|
||||
}
|
||||
@ -1,238 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
path "github.com/ipfs/go-path"
|
||||
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
|
||||
isd "github.com/jbenet/go-is-domain"
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
routing "github.com/libp2p/go-libp2p-core/routing"
|
||||
)
|
||||
|
||||
// mpns (a multi-protocol NameSystem) implements generic IPFS naming.
|
||||
//
|
||||
// Uses several Resolvers:
|
||||
// (a) IPFS routing naming: SFS-like PKI names.
|
||||
// (b) dns domains: resolves using links in DNS TXT records
|
||||
// (c) proquints: interprets string as the raw byte data.
|
||||
//
|
||||
// It can only publish to: (a) IPFS routing naming.
|
||||
//
|
||||
type mpns struct {
|
||||
dnsResolver, proquintResolver, ipnsResolver resolver
|
||||
ipnsPublisher Publisher
|
||||
|
||||
staticMap map[string]path.Path
|
||||
cache *lru.Cache
|
||||
}
|
||||
|
||||
// NewNameSystem will construct the IPFS naming system based on Routing
|
||||
func NewNameSystem(r routing.ValueStore, ds ds.Datastore, cachesize int) NameSystem {
|
||||
var (
|
||||
cache *lru.Cache
|
||||
staticMap map[string]path.Path
|
||||
)
|
||||
if cachesize > 0 {
|
||||
cache, _ = lru.New(cachesize)
|
||||
}
|
||||
|
||||
// Prewarm namesys cache with static records for deterministic tests and debugging.
|
||||
// Useful for testing things like DNSLink without real DNS lookup.
|
||||
// Example:
|
||||
// IPFS_NS_MAP="dnslink-test.example.com:/ipfs/bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am"
|
||||
if list := os.Getenv("IPFS_NS_MAP"); list != "" {
|
||||
staticMap = make(map[string]path.Path)
|
||||
for _, pair := range strings.Split(list, ",") {
|
||||
mapping := strings.SplitN(pair, ":", 2)
|
||||
key := mapping[0]
|
||||
value := path.FromString(mapping[1])
|
||||
staticMap[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
return &mpns{
|
||||
dnsResolver: NewDNSResolver(),
|
||||
proquintResolver: new(ProquintResolver),
|
||||
ipnsResolver: NewIpnsResolver(r),
|
||||
ipnsPublisher: NewIpnsPublisher(r, ds),
|
||||
staticMap: staticMap,
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultResolverCacheTTL defines max ttl of a record placed in namesys cache.
|
||||
const DefaultResolverCacheTTL = time.Minute
|
||||
|
||||
// Resolve implements Resolver.
|
||||
func (ns *mpns) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) {
|
||||
if strings.HasPrefix(name, "/ipfs/") {
|
||||
return path.ParsePath(name)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(name, "/") {
|
||||
return path.ParsePath("/ipfs/" + name)
|
||||
}
|
||||
|
||||
return resolve(ctx, ns, name, opts.ProcessOpts(options))
|
||||
}
|
||||
|
||||
func (ns *mpns) ResolveAsync(ctx context.Context, name string, options ...opts.ResolveOpt) <-chan Result {
|
||||
if strings.HasPrefix(name, "/ipfs/") {
|
||||
p, err := path.ParsePath(name)
|
||||
res := make(chan Result, 1)
|
||||
res <- Result{p, err}
|
||||
close(res)
|
||||
return res
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(name, "/") {
|
||||
p, err := path.ParsePath("/ipfs/" + name)
|
||||
res := make(chan Result, 1)
|
||||
res <- Result{p, err}
|
||||
close(res)
|
||||
return res
|
||||
}
|
||||
|
||||
return resolveAsync(ctx, ns, name, opts.ProcessOpts(options))
|
||||
}
|
||||
|
||||
// resolveOnce implements resolver.
|
||||
func (ns *mpns) resolveOnceAsync(ctx context.Context, name string, options opts.ResolveOpts) <-chan onceResult {
|
||||
out := make(chan onceResult, 1)
|
||||
|
||||
if !strings.HasPrefix(name, ipnsPrefix) {
|
||||
name = ipnsPrefix + name
|
||||
}
|
||||
segments := strings.SplitN(name, "/", 4)
|
||||
if len(segments) < 3 || segments[0] != "" {
|
||||
log.Debugf("invalid name syntax for %s", name)
|
||||
out <- onceResult{err: ErrResolveFailed}
|
||||
close(out)
|
||||
return out
|
||||
}
|
||||
|
||||
key := segments[2]
|
||||
|
||||
// Resolver selection:
|
||||
// 1. if it is a PeerID/CID/multihash resolve through "ipns".
|
||||
// 2. if it is a domain name, resolve through "dns"
|
||||
// 3. otherwise resolve through the "proquint" resolver
|
||||
|
||||
var res resolver
|
||||
ipnsKey, err := peer.Decode(key)
|
||||
|
||||
// CIDs in IPNS are expected to have libp2p-key multicodec
|
||||
// We ease the transition by returning a more meaningful error with a valid CID
|
||||
if err != nil && err.Error() == "can't convert CID of type protobuf to a peer ID" {
|
||||
ipnsCid, cidErr := cid.Decode(key)
|
||||
if cidErr == nil && ipnsCid.Version() == 1 && ipnsCid.Type() != cid.Libp2pKey {
|
||||
fixedCid := cid.NewCidV1(cid.Libp2pKey, ipnsCid.Hash()).String()
|
||||
codecErr := fmt.Errorf("peer ID represented as CIDv1 require libp2p-key multicodec: retry with /ipns/%s", fixedCid)
|
||||
log.Debugf("RoutingResolver: could not convert public key hash %s to peer ID: %s\n", key, codecErr)
|
||||
out <- onceResult{err: codecErr}
|
||||
close(out)
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
cacheKey := key
|
||||
if err == nil {
|
||||
cacheKey = string(ipnsKey)
|
||||
}
|
||||
|
||||
if p, ok := ns.cacheGet(cacheKey); ok {
|
||||
var err error
|
||||
if len(segments) > 3 {
|
||||
p, err = path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[3])
|
||||
}
|
||||
|
||||
out <- onceResult{value: p, err: err}
|
||||
close(out)
|
||||
return out
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
res = ns.ipnsResolver
|
||||
} else if isd.IsDomain(key) {
|
||||
res = ns.dnsResolver
|
||||
} else {
|
||||
res = ns.proquintResolver
|
||||
}
|
||||
|
||||
resCh := res.resolveOnceAsync(ctx, key, options)
|
||||
var best onceResult
|
||||
go func() {
|
||||
defer close(out)
|
||||
for {
|
||||
select {
|
||||
case res, ok := <-resCh:
|
||||
if !ok {
|
||||
if best != (onceResult{}) {
|
||||
ns.cacheSet(cacheKey, best.value, best.ttl)
|
||||
}
|
||||
return
|
||||
}
|
||||
if res.err == nil {
|
||||
best = res
|
||||
}
|
||||
p := res.value
|
||||
err := res.err
|
||||
ttl := res.ttl
|
||||
|
||||
// Attach rest of the path
|
||||
if len(segments) > 3 {
|
||||
p, err = path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[3])
|
||||
}
|
||||
|
||||
emitOnceResult(ctx, out, onceResult{value: p, ttl: ttl, err: err})
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func emitOnceResult(ctx context.Context, outCh chan<- onceResult, r onceResult) {
|
||||
select {
|
||||
case outCh <- r:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
|
||||
// Publish implements Publisher
|
||||
func (ns *mpns) Publish(ctx context.Context, name ci.PrivKey, value path.Path) error {
|
||||
return ns.PublishWithEOL(ctx, name, value, time.Now().Add(DefaultRecordEOL))
|
||||
}
|
||||
|
||||
func (ns *mpns) PublishWithEOL(ctx context.Context, name ci.PrivKey, value path.Path, eol time.Time) error {
|
||||
id, err := peer.IDFromPrivateKey(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ns.ipnsPublisher.PublishWithEOL(ctx, name, value, eol); err != nil {
|
||||
// Invalidate the cache. Publishing may _partially_ succeed but
|
||||
// still return an error.
|
||||
ns.cacheInvalidate(string(id))
|
||||
return err
|
||||
}
|
||||
ttl := DefaultResolverCacheTTL
|
||||
if setTTL, ok := checkCtxTTL(ctx); ok {
|
||||
ttl = setTTL
|
||||
}
|
||||
if ttEol := time.Until(eol); ttEol < ttl {
|
||||
ttl = ttEol
|
||||
}
|
||||
ns.cacheSet(string(id), value, ttl)
|
||||
return nil
|
||||
}
|
||||
@ -1,169 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
dssync "github.com/ipfs/go-datastore/sync"
|
||||
offroute "github.com/ipfs/go-ipfs-routing/offline"
|
||||
ipns "github.com/ipfs/go-ipns"
|
||||
path "github.com/ipfs/go-path"
|
||||
unixfs "github.com/ipfs/go-unixfs"
|
||||
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
pstoremem "github.com/libp2p/go-libp2p-peerstore/pstoremem"
|
||||
record "github.com/libp2p/go-libp2p-record"
|
||||
)
|
||||
|
||||
type mockResolver struct {
|
||||
entries map[string]string
|
||||
}
|
||||
|
||||
func testResolution(t *testing.T, resolver Resolver, name string, depth uint, expected string, expError error) {
|
||||
t.Helper()
|
||||
p, err := resolver.Resolve(context.Background(), name, opts.Depth(depth))
|
||||
if err != expError {
|
||||
t.Fatal(fmt.Errorf(
|
||||
"expected %s with a depth of %d to have a '%s' error, but got '%s'",
|
||||
name, depth, expError, err))
|
||||
}
|
||||
if p.String() != expected {
|
||||
t.Fatal(fmt.Errorf(
|
||||
"%s with depth %d resolved to %s != %s",
|
||||
name, depth, p.String(), expected))
|
||||
}
|
||||
}
|
||||
|
||||
func (r *mockResolver) resolveOnceAsync(ctx context.Context, name string, options opts.ResolveOpts) <-chan onceResult {
|
||||
p, err := path.ParsePath(r.entries[name])
|
||||
out := make(chan onceResult, 1)
|
||||
out <- onceResult{value: p, err: err}
|
||||
close(out)
|
||||
return out
|
||||
}
|
||||
|
||||
func mockResolverOne() *mockResolver {
|
||||
return &mockResolver{
|
||||
entries: map[string]string{
|
||||
"QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy": "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj",
|
||||
"QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n": "/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy",
|
||||
"QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD": "/ipns/ipfs.io",
|
||||
"QmQ4QZh8nrsczdUEwTyfBope4THUhqxqc1fx6qYhhzZQei": "/ipfs/QmP3ouCnU8NNLsW6261pAx2pNLV2E4dQoisB1sgda12Act",
|
||||
"12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5": "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", // ed25519+identity multihash
|
||||
"bafzbeickencdqw37dpz3ha36ewrh4undfjt2do52chtcky4rxkj447qhdm": "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", // cidv1 in base32 with libp2p-key multicodec
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func mockResolverTwo() *mockResolver {
|
||||
return &mockResolver{
|
||||
entries: map[string]string{
|
||||
"ipfs.io": "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestNamesysResolution(t *testing.T) {
|
||||
r := &mpns{
|
||||
ipnsResolver: mockResolverOne(),
|
||||
dnsResolver: mockResolverTwo(),
|
||||
}
|
||||
|
||||
testResolution(t, r, "Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil)
|
||||
testResolution(t, r, "/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil)
|
||||
testResolution(t, r, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil)
|
||||
testResolution(t, r, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", 1, "/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy", ErrResolveRecursion)
|
||||
testResolution(t, r, "/ipns/ipfs.io", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil)
|
||||
testResolution(t, r, "/ipns/ipfs.io", 1, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", ErrResolveRecursion)
|
||||
testResolution(t, r, "/ipns/ipfs.io", 2, "/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy", ErrResolveRecursion)
|
||||
testResolution(t, r, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil)
|
||||
testResolution(t, r, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", 1, "/ipns/ipfs.io", ErrResolveRecursion)
|
||||
testResolution(t, r, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", 2, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", ErrResolveRecursion)
|
||||
testResolution(t, r, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", 3, "/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy", ErrResolveRecursion)
|
||||
testResolution(t, r, "/ipns/12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5", 1, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", ErrResolveRecursion)
|
||||
testResolution(t, r, "/ipns/bafzbeickencdqw37dpz3ha36ewrh4undfjt2do52chtcky4rxkj447qhdm", 1, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", ErrResolveRecursion)
|
||||
}
|
||||
|
||||
func TestPublishWithCache0(t *testing.T) {
|
||||
dst := dssync.MutexWrap(ds.NewMapDatastore())
|
||||
priv, _, err := ci.GenerateKeyPair(ci.RSA, 2048)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ps := pstoremem.NewPeerstore()
|
||||
pid, err := peer.IDFromPrivateKey(priv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ps.AddPrivKey(pid, priv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
routing := offroute.NewOfflineRouter(dst, record.NamespacedValidator{
|
||||
"ipns": ipns.Validator{KeyBook: ps},
|
||||
"pk": record.PublicKeyValidator{},
|
||||
})
|
||||
|
||||
nsys := NewNameSystem(routing, dst, 0)
|
||||
p, err := path.ParsePath(unixfs.EmptyDirNode().Cid().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = nsys.Publish(context.Background(), priv, p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishWithTTL(t *testing.T) {
|
||||
dst := dssync.MutexWrap(ds.NewMapDatastore())
|
||||
priv, _, err := ci.GenerateKeyPair(ci.RSA, 2048)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ps := pstoremem.NewPeerstore()
|
||||
pid, err := peer.IDFromPrivateKey(priv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ps.AddPrivKey(pid, priv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
routing := offroute.NewOfflineRouter(dst, record.NamespacedValidator{
|
||||
"ipns": ipns.Validator{KeyBook: ps},
|
||||
"pk": record.PublicKeyValidator{},
|
||||
})
|
||||
|
||||
nsys := NewNameSystem(routing, dst, 128)
|
||||
p, err := path.ParsePath(unixfs.EmptyDirNode().Cid().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ttl := 1 * time.Second
|
||||
eol := time.Now().Add(2 * time.Second)
|
||||
|
||||
ctx := context.WithValue(context.Background(), "ipns-publish-ttl", ttl)
|
||||
err = nsys.Publish(ctx, priv, p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ientry, ok := nsys.(*mpns).cache.Get(string(pid))
|
||||
if !ok {
|
||||
t.Fatal("cache get failed")
|
||||
}
|
||||
entry, ok := ientry.(cacheEntry)
|
||||
if !ok {
|
||||
t.Fatal("bad cache item returned")
|
||||
}
|
||||
if entry.eol.Sub(eol) > 10*time.Millisecond {
|
||||
t.Fatalf("bad cache ttl: expected %s, got %s", eol, entry.eol)
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
proquint "github.com/bren2010/proquint"
|
||||
path "github.com/ipfs/go-path"
|
||||
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
|
||||
)
|
||||
|
||||
type ProquintResolver struct{}
|
||||
|
||||
// Resolve implements Resolver.
|
||||
func (r *ProquintResolver) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) {
|
||||
return resolve(ctx, r, name, opts.ProcessOpts(options))
|
||||
}
|
||||
|
||||
// resolveOnce implements resolver. Decodes the proquint string.
|
||||
func (r *ProquintResolver) resolveOnceAsync(ctx context.Context, name string, options opts.ResolveOpts) <-chan onceResult {
|
||||
out := make(chan onceResult, 1)
|
||||
defer close(out)
|
||||
|
||||
ok, err := proquint.IsProquint(name)
|
||||
if err != nil || !ok {
|
||||
out <- onceResult{err: errors.New("not a valid proquint string")}
|
||||
return out
|
||||
}
|
||||
// Return a 0 TTL as caching this result is pointless.
|
||||
out <- onceResult{value: path.FromString(string(proquint.Decode(name)))}
|
||||
return out
|
||||
}
|
||||
@ -1,309 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
dsquery "github.com/ipfs/go-datastore/query"
|
||||
pin "github.com/ipfs/go-ipfs-pinner"
|
||||
ipns "github.com/ipfs/go-ipns"
|
||||
pb "github.com/ipfs/go-ipns/pb"
|
||||
path "github.com/ipfs/go-path"
|
||||
ft "github.com/ipfs/go-unixfs"
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
routing "github.com/libp2p/go-libp2p-core/routing"
|
||||
base32 "github.com/whyrusleeping/base32"
|
||||
)
|
||||
|
||||
const ipnsPrefix = "/ipns/"
|
||||
|
||||
const DefaultRecordEOL = 24 * time.Hour
|
||||
|
||||
// IpnsPublisher is capable of publishing and resolving names to the IPFS
|
||||
// routing system.
|
||||
type IpnsPublisher struct {
|
||||
routing routing.ValueStore
|
||||
ds ds.Datastore
|
||||
|
||||
// Used to ensure we assign IPNS records *sequential* sequence numbers.
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewIpnsPublisher constructs a publisher for the IPFS Routing name system.
|
||||
func NewIpnsPublisher(route routing.ValueStore, ds ds.Datastore) *IpnsPublisher {
|
||||
if ds == nil {
|
||||
panic("nil datastore")
|
||||
}
|
||||
return &IpnsPublisher{routing: route, ds: ds}
|
||||
}
|
||||
|
||||
// Publish implements Publisher. Accepts a keypair and a value,
|
||||
// and publishes it out to the routing system
|
||||
func (p *IpnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value path.Path) error {
|
||||
log.Debugf("Publish %s", value)
|
||||
return p.PublishWithEOL(ctx, k, value, time.Now().Add(DefaultRecordEOL))
|
||||
}
|
||||
|
||||
func IpnsDsKey(id peer.ID) ds.Key {
|
||||
return ds.NewKey("/ipns/" + base32.RawStdEncoding.EncodeToString([]byte(id)))
|
||||
}
|
||||
|
||||
// PublishedNames returns the latest IPNS records published by this node and
|
||||
// their expiration times.
|
||||
//
|
||||
// This method will not search the routing system for records published by other
|
||||
// nodes.
|
||||
func (p *IpnsPublisher) ListPublished(ctx context.Context) (map[peer.ID]*pb.IpnsEntry, error) {
|
||||
query, err := p.ds.Query(dsquery.Query{
|
||||
Prefix: ipnsPrefix,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer query.Close()
|
||||
|
||||
records := make(map[peer.ID]*pb.IpnsEntry)
|
||||
for {
|
||||
select {
|
||||
case result, ok := <-query.Next():
|
||||
if !ok {
|
||||
return records, nil
|
||||
}
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
e := new(pb.IpnsEntry)
|
||||
if err := proto.Unmarshal(result.Value, e); err != nil {
|
||||
// Might as well return what we can.
|
||||
log.Error("found an invalid IPNS entry:", err)
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(result.Key, ipnsPrefix) {
|
||||
log.Errorf("datastore query for keys with prefix %s returned a key: %s", ipnsPrefix, result.Key)
|
||||
continue
|
||||
}
|
||||
k := result.Key[len(ipnsPrefix):]
|
||||
pid, err := base32.RawStdEncoding.DecodeString(k)
|
||||
if err != nil {
|
||||
log.Errorf("ipns ds key invalid: %s", result.Key)
|
||||
continue
|
||||
}
|
||||
records[peer.ID(pid)] = e
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetPublished returns the record this node has published corresponding to the
|
||||
// given peer ID.
|
||||
//
|
||||
// If `checkRouting` is true and we have no existing record, this method will
|
||||
// check the routing system for any existing records.
|
||||
func (p *IpnsPublisher) GetPublished(ctx context.Context, id peer.ID, checkRouting bool) (*pb.IpnsEntry, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
||||
defer cancel()
|
||||
|
||||
value, err := p.ds.Get(IpnsDsKey(id))
|
||||
switch err {
|
||||
case nil:
|
||||
case ds.ErrNotFound:
|
||||
if !checkRouting {
|
||||
return nil, nil
|
||||
}
|
||||
ipnskey := ipns.RecordKey(id)
|
||||
value, err = p.routing.GetValue(ctx, ipnskey)
|
||||
if err != nil {
|
||||
// Not found or other network issue. Can't really do
|
||||
// anything about this case.
|
||||
if err != routing.ErrNotFound {
|
||||
log.Debugf("error when determining the last published IPNS record for %s: %s", id, err)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
e := new(pb.IpnsEntry)
|
||||
if err := proto.Unmarshal(value, e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (p *IpnsPublisher) updateRecord(ctx context.Context, k ci.PrivKey, value path.Path, eol time.Time) (*pb.IpnsEntry, error) {
|
||||
id, err := peer.IDFromPrivateKey(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
// get previous records sequence number
|
||||
rec, err := p.GetPublished(ctx, id, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
seqno := rec.GetSequence() // returns 0 if rec is nil
|
||||
if rec != nil && value != path.Path(rec.GetValue()) {
|
||||
// Don't bother incrementing the sequence number unless the
|
||||
// value changes.
|
||||
seqno++
|
||||
}
|
||||
|
||||
// Create record
|
||||
entry, err := ipns.Create(k, []byte(value), seqno, eol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set the TTL
|
||||
// TODO: Make this less hacky.
|
||||
ttl, ok := checkCtxTTL(ctx)
|
||||
if ok {
|
||||
entry.Ttl = proto.Uint64(uint64(ttl.Nanoseconds()))
|
||||
}
|
||||
|
||||
data, err := proto.Marshal(entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Put the new record.
|
||||
key := IpnsDsKey(id)
|
||||
if err := p.ds.Put(key, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p.ds.Sync(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entry, nil
|
||||
}
|
||||
|
||||
// PublishWithEOL is a temporary stand in for the ipns records implementation
|
||||
// see here for more details: https://github.com/ipfs/specs/tree/master/records
|
||||
func (p *IpnsPublisher) PublishWithEOL(ctx context.Context, k ci.PrivKey, value path.Path, eol time.Time) error {
|
||||
record, err := p.updateRecord(ctx, k, value, eol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return PutRecordToRouting(ctx, p.routing, k.GetPublic(), record)
|
||||
}
|
||||
|
||||
// setting the TTL on published records is an experimental feature.
|
||||
// as such, i'm using the context to wire it through to avoid changing too
|
||||
// much code along the way.
|
||||
func checkCtxTTL(ctx context.Context) (time.Duration, bool) {
|
||||
v := ctx.Value("ipns-publish-ttl")
|
||||
if v == nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
d, ok := v.(time.Duration)
|
||||
return d, ok
|
||||
}
|
||||
|
||||
func PutRecordToRouting(ctx context.Context, r routing.ValueStore, k ci.PubKey, entry *pb.IpnsEntry) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
errs := make(chan error, 2) // At most two errors (IPNS, and public key)
|
||||
|
||||
if err := ipns.EmbedPublicKey(k, entry); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
id, err := peer.IDFromPublicKey(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
errs <- PublishEntry(ctx, r, ipns.RecordKey(id), entry)
|
||||
}()
|
||||
|
||||
// Publish the public key if a public key cannot be extracted from the ID
|
||||
// TODO: once v0.4.16 is widespread enough, we can stop doing this
|
||||
// and at that point we can even deprecate the /pk/ namespace in the dht
|
||||
//
|
||||
// NOTE: This check actually checks if the public key has been embedded
|
||||
// in the IPNS entry. This check is sufficient because we embed the
|
||||
// public key in the IPNS entry if it can't be extracted from the ID.
|
||||
if entry.PubKey != nil {
|
||||
go func() {
|
||||
errs <- PublishPublicKey(ctx, r, PkKeyForID(id), k)
|
||||
}()
|
||||
|
||||
if err := waitOnErrChan(ctx, errs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return waitOnErrChan(ctx, errs)
|
||||
}
|
||||
|
||||
func waitOnErrChan(ctx context.Context, errs chan error) error {
|
||||
select {
|
||||
case err := <-errs:
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func PublishPublicKey(ctx context.Context, r routing.ValueStore, k string, pubk ci.PubKey) error {
|
||||
log.Debugf("Storing pubkey at: %s", k)
|
||||
pkbytes, err := pubk.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Store associated public key
|
||||
return r.PutValue(ctx, k, pkbytes)
|
||||
}
|
||||
|
||||
func PublishEntry(ctx context.Context, r routing.ValueStore, ipnskey string, rec *pb.IpnsEntry) error {
|
||||
data, err := proto.Marshal(rec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("Storing ipns entry at: %s", ipnskey)
|
||||
// Store ipns entry at "/ipns/"+h(pubkey)
|
||||
return r.PutValue(ctx, ipnskey, data)
|
||||
}
|
||||
|
||||
// InitializeKeyspace sets the ipns record for the given key to
|
||||
// point to an empty directory.
|
||||
// TODO: this doesnt feel like it belongs here
|
||||
func InitializeKeyspace(ctx context.Context, pub Publisher, pins pin.Pinner, key ci.PrivKey) error {
|
||||
emptyDir := ft.EmptyDirNode()
|
||||
|
||||
// pin recursively because this might already be pinned
|
||||
// and doing a direct pin would throw an error in that case
|
||||
err := pins.Pin(ctx, emptyDir, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = pins.Flush(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pub.Publish(ctx, key, path.FromCid(emptyDir.Cid()))
|
||||
}
|
||||
|
||||
// PkKeyForID returns the public key routing key for the given peer ID.
|
||||
func PkKeyForID(id peer.ID) string {
|
||||
return "/pk/" + string(id)
|
||||
}
|
||||
@ -1,155 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"github.com/ipfs/go-path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
dssync "github.com/ipfs/go-datastore/sync"
|
||||
dshelp "github.com/ipfs/go-ipfs-ds-help"
|
||||
mockrouting "github.com/ipfs/go-ipfs-routing/mock"
|
||||
ipns "github.com/ipfs/go-ipns"
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
testutil "github.com/libp2p/go-libp2p-testing/net"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
type identity struct {
|
||||
testutil.PeerNetParams
|
||||
}
|
||||
|
||||
func (p *identity) ID() peer.ID {
|
||||
return p.PeerNetParams.ID
|
||||
}
|
||||
|
||||
func (p *identity) Address() ma.Multiaddr {
|
||||
return p.Addr
|
||||
}
|
||||
|
||||
func (p *identity) PrivateKey() ci.PrivKey {
|
||||
return p.PrivKey
|
||||
}
|
||||
|
||||
func (p *identity) PublicKey() ci.PubKey {
|
||||
return p.PubKey
|
||||
}
|
||||
|
||||
func testNamekeyPublisher(t *testing.T, keyType int, expectedErr error, expectedExistence bool) {
|
||||
// Context
|
||||
ctx := context.Background()
|
||||
|
||||
// Private key
|
||||
privKey, pubKey, err := ci.GenerateKeyPairWithReader(keyType, 2048, rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// ID
|
||||
id, err := peer.IDFromPublicKey(pubKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Value
|
||||
value := []byte("ipfs/TESTING")
|
||||
|
||||
// Seqnum
|
||||
seqnum := uint64(0)
|
||||
|
||||
// Eol
|
||||
eol := time.Now().Add(24 * time.Hour)
|
||||
|
||||
// Routing value store
|
||||
p := testutil.PeerNetParams{
|
||||
ID: id,
|
||||
PrivKey: privKey,
|
||||
PubKey: pubKey,
|
||||
Addr: testutil.ZeroLocalTCPAddress,
|
||||
}
|
||||
|
||||
dstore := dssync.MutexWrap(ds.NewMapDatastore())
|
||||
serv := mockrouting.NewServer()
|
||||
r := serv.ClientWithDatastore(context.Background(), &identity{p}, dstore)
|
||||
|
||||
entry, err := ipns.Create(privKey, value, seqnum, eol)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = PutRecordToRouting(ctx, r, pubKey, entry)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check for namekey existence in value store
|
||||
namekey := PkKeyForID(id)
|
||||
_, err = r.GetValue(ctx, namekey)
|
||||
if err != expectedErr {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Also check datastore for completeness
|
||||
key := dshelp.NewKeyFromBinary([]byte(namekey))
|
||||
exists, err := dstore.Has(key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if exists != expectedExistence {
|
||||
t.Fatal("Unexpected key existence in datastore")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRSAPublisher(t *testing.T) {
|
||||
testNamekeyPublisher(t, ci.RSA, nil, true)
|
||||
}
|
||||
|
||||
func TestEd22519Publisher(t *testing.T) {
|
||||
testNamekeyPublisher(t, ci.Ed25519, ds.ErrNotFound, false)
|
||||
}
|
||||
|
||||
func TestAsyncDS(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
rt := mockrouting.NewServer().Client(testutil.RandIdentityOrFatal(t))
|
||||
ds := &checkSyncDS{
|
||||
Datastore: ds.NewMapDatastore(),
|
||||
syncKeys: make(map[ds.Key]struct{}),
|
||||
}
|
||||
publisher := NewIpnsPublisher(rt, ds)
|
||||
|
||||
ipnsFakeID := testutil.RandIdentityOrFatal(t)
|
||||
ipnsVal, err := path.ParsePath("/ipns/foo.bar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := publisher.Publish(ctx, ipnsFakeID.PrivateKey(), ipnsVal); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ipnsKey := IpnsDsKey(ipnsFakeID.ID())
|
||||
|
||||
for k := range ds.syncKeys {
|
||||
if k.IsAncestorOf(ipnsKey) || k.Equal(ipnsKey) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
t.Fatal("ipns key not synced")
|
||||
}
|
||||
|
||||
type checkSyncDS struct {
|
||||
ds.Datastore
|
||||
syncKeys map[ds.Key]struct{}
|
||||
}
|
||||
|
||||
func (d *checkSyncDS) Sync(prefix ds.Key) error {
|
||||
d.syncKeys[prefix] = struct{}{}
|
||||
return d.Datastore.Sync(prefix)
|
||||
}
|
||||
@ -1,168 +0,0 @@
|
||||
package republisher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
keystore "github.com/ipfs/go-ipfs/keystore"
|
||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
||||
path "github.com/ipfs/go-path"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
ipns "github.com/ipfs/go-ipns"
|
||||
pb "github.com/ipfs/go-ipns/pb"
|
||||
logging "github.com/ipfs/go-log"
|
||||
goprocess "github.com/jbenet/goprocess"
|
||||
gpctx "github.com/jbenet/goprocess/context"
|
||||
ic "github.com/libp2p/go-libp2p-core/crypto"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
)
|
||||
|
||||
var errNoEntry = errors.New("no previous entry")
|
||||
|
||||
var log = logging.Logger("ipns-repub")
|
||||
|
||||
// DefaultRebroadcastInterval is the default interval at which we rebroadcast IPNS records
|
||||
var DefaultRebroadcastInterval = time.Hour * 4
|
||||
|
||||
// InitialRebroadcastDelay is the delay before first broadcasting IPNS records on start
|
||||
var InitialRebroadcastDelay = time.Minute * 1
|
||||
|
||||
// FailureRetryInterval is the interval at which we retry IPNS records broadcasts (when they fail)
|
||||
var FailureRetryInterval = time.Minute * 5
|
||||
|
||||
// DefaultRecordLifetime is the default lifetime for IPNS records
|
||||
const DefaultRecordLifetime = time.Hour * 24
|
||||
|
||||
type Republisher struct {
|
||||
ns namesys.Publisher
|
||||
ds ds.Datastore
|
||||
self ic.PrivKey
|
||||
ks keystore.Keystore
|
||||
|
||||
Interval time.Duration
|
||||
|
||||
// how long records that are republished should be valid for
|
||||
RecordLifetime time.Duration
|
||||
}
|
||||
|
||||
// NewRepublisher creates a new Republisher
|
||||
func NewRepublisher(ns namesys.Publisher, ds ds.Datastore, self ic.PrivKey, ks keystore.Keystore) *Republisher {
|
||||
return &Republisher{
|
||||
ns: ns,
|
||||
ds: ds,
|
||||
self: self,
|
||||
ks: ks,
|
||||
Interval: DefaultRebroadcastInterval,
|
||||
RecordLifetime: DefaultRecordLifetime,
|
||||
}
|
||||
}
|
||||
|
||||
func (rp *Republisher) Run(proc goprocess.Process) {
|
||||
timer := time.NewTimer(InitialRebroadcastDelay)
|
||||
defer timer.Stop()
|
||||
if rp.Interval < InitialRebroadcastDelay {
|
||||
timer.Reset(rp.Interval)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-timer.C:
|
||||
timer.Reset(rp.Interval)
|
||||
err := rp.republishEntries(proc)
|
||||
if err != nil {
|
||||
log.Info("republisher failed to republish: ", err)
|
||||
if FailureRetryInterval < rp.Interval {
|
||||
timer.Reset(FailureRetryInterval)
|
||||
}
|
||||
}
|
||||
case <-proc.Closing():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (rp *Republisher) republishEntries(p goprocess.Process) error {
|
||||
ctx, cancel := context.WithCancel(gpctx.OnClosingContext(p))
|
||||
defer cancel()
|
||||
|
||||
// TODO: Use rp.ipns.ListPublished(). We can't currently *do* that
|
||||
// because:
|
||||
// 1. There's no way to get keys from the keystore by ID.
|
||||
// 2. We don't actually have access to the IPNS publisher.
|
||||
err := rp.republishEntry(ctx, rp.self)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rp.ks != nil {
|
||||
keyNames, err := rp.ks.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, name := range keyNames {
|
||||
priv, err := rp.ks.Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = rp.republishEntry(ctx, priv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rp *Republisher) republishEntry(ctx context.Context, priv ic.PrivKey) error {
|
||||
id, err := peer.IDFromPrivateKey(priv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("republishing ipns entry for %s", id)
|
||||
|
||||
// Look for it locally only
|
||||
e, err := rp.getLastIPNSEntry(id)
|
||||
if err != nil {
|
||||
if err == errNoEntry {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
p := path.Path(e.GetValue())
|
||||
prevEol, err := ipns.GetEOL(e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update record with same sequence number
|
||||
eol := time.Now().Add(rp.RecordLifetime)
|
||||
if prevEol.After(eol) {
|
||||
eol = prevEol
|
||||
}
|
||||
return rp.ns.PublishWithEOL(ctx, priv, p, eol)
|
||||
}
|
||||
|
||||
func (rp *Republisher) getLastIPNSEntry(id peer.ID) (*pb.IpnsEntry, error) {
|
||||
// Look for it locally only
|
||||
val, err := rp.ds.Get(namesys.IpnsDsKey(id))
|
||||
switch err {
|
||||
case nil:
|
||||
case ds.ErrNotFound:
|
||||
return nil, errNoEntry
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e := new(pb.IpnsEntry)
|
||||
if err := proto.Unmarshal(val, e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
@ -1,245 +0,0 @@
|
||||
package republisher_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
goprocess "github.com/jbenet/goprocess"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
|
||||
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-ipns"
|
||||
"github.com/ipfs/go-ipns/pb"
|
||||
path "github.com/ipfs/go-path"
|
||||
|
||||
"github.com/ipfs/go-ipfs/core"
|
||||
"github.com/ipfs/go-ipfs/core/bootstrap"
|
||||
mock "github.com/ipfs/go-ipfs/core/mock"
|
||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
||||
. "github.com/ipfs/go-ipfs/namesys/republisher"
|
||||
)
|
||||
|
||||
func TestRepublish(t *testing.T) {
|
||||
// set cache life to zero for testing low-period repubs
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create network
|
||||
mn := mocknet.New(ctx)
|
||||
|
||||
var nodes []*core.IpfsNode
|
||||
for i := 0; i < 10; i++ {
|
||||
nd, err := mock.MockPublicNode(ctx, mn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nd.Namesys = namesys.NewNameSystem(nd.Routing, nd.Repo.Datastore(), 0)
|
||||
|
||||
nodes = append(nodes, nd)
|
||||
}
|
||||
|
||||
if err := mn.LinkAll(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bsinf := bootstrap.BootstrapConfigWithPeers(
|
||||
[]peer.AddrInfo{
|
||||
nodes[0].Peerstore.PeerInfo(nodes[0].Identity),
|
||||
},
|
||||
)
|
||||
|
||||
for _, n := range nodes[1:] {
|
||||
if err := n.Bootstrap(bsinf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// have one node publish a record that is valid for 1 second
|
||||
publisher := nodes[3]
|
||||
p := path.FromString("/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn") // does not need to be valid
|
||||
rp := namesys.NewIpnsPublisher(publisher.Routing, publisher.Repo.Datastore())
|
||||
name := "/ipns/" + publisher.Identity.Pretty()
|
||||
|
||||
// Retry in case the record expires before we can fetch it. This can
|
||||
// happen when running the test on a slow machine.
|
||||
var expiration time.Time
|
||||
timeout := time.Second
|
||||
for {
|
||||
expiration = time.Now().Add(time.Second)
|
||||
err := rp.PublishWithEOL(ctx, publisher.PrivateKey, p, expiration)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = verifyResolution(nodes, name, p)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
if time.Now().After(expiration) {
|
||||
timeout *= 2
|
||||
continue
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now wait a second, the records will be invalid and we should fail to resolve
|
||||
time.Sleep(timeout)
|
||||
if err := verifyResolutionFails(nodes, name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The republishers that are contained within the nodes have their timeout set
|
||||
// to 12 hours. Instead of trying to tweak those, we're just going to pretend
|
||||
// they don't exist and make our own.
|
||||
repub := NewRepublisher(rp, publisher.Repo.Datastore(), publisher.PrivateKey, publisher.Repo.Keystore())
|
||||
repub.Interval = time.Second
|
||||
repub.RecordLifetime = time.Second * 5
|
||||
|
||||
proc := goprocess.Go(repub.Run)
|
||||
defer proc.Close()
|
||||
|
||||
// now wait a couple seconds for it to fire
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
// we should be able to resolve them now
|
||||
if err := verifyResolution(nodes, name, p); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLongEOLRepublish(t *testing.T) {
|
||||
// set cache life to zero for testing low-period repubs
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create network
|
||||
mn := mocknet.New(ctx)
|
||||
|
||||
var nodes []*core.IpfsNode
|
||||
for i := 0; i < 10; i++ {
|
||||
nd, err := mock.MockPublicNode(ctx, mn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nd.Namesys = namesys.NewNameSystem(nd.Routing, nd.Repo.Datastore(), 0)
|
||||
|
||||
nodes = append(nodes, nd)
|
||||
}
|
||||
|
||||
if err := mn.LinkAll(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bsinf := bootstrap.BootstrapConfigWithPeers(
|
||||
[]peer.AddrInfo{
|
||||
nodes[0].Peerstore.PeerInfo(nodes[0].Identity),
|
||||
},
|
||||
)
|
||||
|
||||
for _, n := range nodes[1:] {
|
||||
if err := n.Bootstrap(bsinf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// have one node publish a record that is valid for 1 second
|
||||
publisher := nodes[3]
|
||||
p := path.FromString("/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn") // does not need to be valid
|
||||
rp := namesys.NewIpnsPublisher(publisher.Routing, publisher.Repo.Datastore())
|
||||
name := "/ipns/" + publisher.Identity.Pretty()
|
||||
|
||||
expiration := time.Now().Add(time.Hour)
|
||||
err := rp.PublishWithEOL(ctx, publisher.PrivateKey, p, expiration)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = verifyResolution(nodes, name, p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The republishers that are contained within the nodes have their timeout set
|
||||
// to 12 hours. Instead of trying to tweak those, we're just going to pretend
|
||||
// they don't exist and make our own.
|
||||
repub := NewRepublisher(rp, publisher.Repo.Datastore(), publisher.PrivateKey, publisher.Repo.Keystore())
|
||||
repub.Interval = time.Millisecond * 500
|
||||
repub.RecordLifetime = time.Second
|
||||
|
||||
proc := goprocess.Go(repub.Run)
|
||||
defer proc.Close()
|
||||
|
||||
// now wait a couple seconds for it to fire a few times
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
err = verifyResolution(nodes, name, p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
entry, err := getLastIPNSEntry(publisher.Repo.Datastore(), publisher.Identity)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finalEol, err := ipns.GetEOL(entry)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !finalEol.Equal(expiration) {
|
||||
t.Fatal("expiration time modified")
|
||||
}
|
||||
}
|
||||
|
||||
func getLastIPNSEntry(dstore ds.Datastore, id peer.ID) (*ipns_pb.IpnsEntry, error) {
|
||||
// Look for it locally only
|
||||
val, err := dstore.Get(namesys.IpnsDsKey(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e := new(ipns_pb.IpnsEntry)
|
||||
if err := proto.Unmarshal(val, e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func verifyResolution(nodes []*core.IpfsNode, key string, exp path.Path) error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
for _, n := range nodes {
|
||||
val, err := n.Namesys.Resolve(ctx, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if val != exp {
|
||||
return errors.New("resolved wrong record")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyResolutionFails(nodes []*core.IpfsNode, key string) error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
for _, n := range nodes {
|
||||
_, err := n.Namesys.Resolve(ctx, key)
|
||||
if err == nil {
|
||||
return errors.New("expected resolution to fail")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
package resolve
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ipfs/go-path"
|
||||
|
||||
"github.com/ipfs/go-ipfs/namesys"
|
||||
)
|
||||
|
||||
// ErrNoNamesys is an explicit error for when an IPFS node doesn't
|
||||
// (yet) have a name system
|
||||
var ErrNoNamesys = errors.New(
|
||||
"core/resolve: no Namesys on IpfsNode - can't resolve ipns entry")
|
||||
|
||||
// ResolveIPNS resolves /ipns paths
|
||||
func ResolveIPNS(ctx context.Context, nsys namesys.NameSystem, p path.Path) (path.Path, error) {
|
||||
if strings.HasPrefix(p.String(), "/ipns/") {
|
||||
// TODO(cryptix): we should be able to query the local cache for the path
|
||||
if nsys == nil {
|
||||
return "", ErrNoNamesys
|
||||
}
|
||||
|
||||
seg := p.Segments()
|
||||
|
||||
if len(seg) < 2 || seg[1] == "" { // just "/<protocol/>" without further segments
|
||||
err := fmt.Errorf("invalid path %q: ipns path missing IPNS ID", p)
|
||||
return "", err
|
||||
}
|
||||
|
||||
extensions := seg[2:]
|
||||
resolvable, err := path.FromSegments("/", seg[0], seg[1])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
respath, err := nsys.Resolve(ctx, resolvable.String())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
segments := append(respath.Segments(), extensions...)
|
||||
p, err = path.FromSegments("/", segments...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
@ -1,123 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
dssync "github.com/ipfs/go-datastore/sync"
|
||||
mockrouting "github.com/ipfs/go-ipfs-routing/mock"
|
||||
ipns "github.com/ipfs/go-ipns"
|
||||
path "github.com/ipfs/go-path"
|
||||
testutil "github.com/libp2p/go-libp2p-testing/net"
|
||||
tnet "github.com/libp2p/go-libp2p-testing/net"
|
||||
)
|
||||
|
||||
func TestRoutingResolve(t *testing.T) {
|
||||
dstore := dssync.MutexWrap(ds.NewMapDatastore())
|
||||
serv := mockrouting.NewServer()
|
||||
id := testutil.RandIdentityOrFatal(t)
|
||||
d := serv.ClientWithDatastore(context.Background(), id, dstore)
|
||||
|
||||
resolver := NewIpnsResolver(d)
|
||||
publisher := NewIpnsPublisher(d, dstore)
|
||||
|
||||
identity := tnet.RandIdentityOrFatal(t)
|
||||
|
||||
h := path.FromString("/ipfs/QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN")
|
||||
err := publisher.Publish(context.Background(), identity.PrivateKey(), h)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
res, err := resolver.Resolve(context.Background(), identity.ID().Pretty())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if res != h {
|
||||
t.Fatal("Got back incorrect value.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrexistingExpiredRecord(t *testing.T) {
|
||||
dstore := dssync.MutexWrap(ds.NewMapDatastore())
|
||||
d := mockrouting.NewServer().ClientWithDatastore(context.Background(), testutil.RandIdentityOrFatal(t), dstore)
|
||||
|
||||
resolver := NewIpnsResolver(d)
|
||||
publisher := NewIpnsPublisher(d, dstore)
|
||||
|
||||
identity := tnet.RandIdentityOrFatal(t)
|
||||
|
||||
// Make an expired record and put it in the datastore
|
||||
h := path.FromString("/ipfs/QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN")
|
||||
eol := time.Now().Add(time.Hour * -1)
|
||||
|
||||
entry, err := ipns.Create(identity.PrivateKey(), []byte(h), 0, eol)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = PutRecordToRouting(context.Background(), d, identity.PublicKey(), entry)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now, with an old record in the system already, try and publish a new one
|
||||
err = publisher.Publish(context.Background(), identity.PrivateKey(), h)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = verifyCanResolve(resolver, identity.ID().Pretty(), h)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrexistingRecord(t *testing.T) {
|
||||
dstore := dssync.MutexWrap(ds.NewMapDatastore())
|
||||
d := mockrouting.NewServer().ClientWithDatastore(context.Background(), testutil.RandIdentityOrFatal(t), dstore)
|
||||
|
||||
resolver := NewIpnsResolver(d)
|
||||
publisher := NewIpnsPublisher(d, dstore)
|
||||
|
||||
identity := tnet.RandIdentityOrFatal(t)
|
||||
|
||||
// Make a good record and put it in the datastore
|
||||
h := path.FromString("/ipfs/QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN")
|
||||
eol := time.Now().Add(time.Hour)
|
||||
entry, err := ipns.Create(identity.PrivateKey(), []byte(h), 0, eol)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = PutRecordToRouting(context.Background(), d, identity.PublicKey(), entry)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now, with an old record in the system already, try and publish a new one
|
||||
err = publisher.Publish(context.Background(), identity.PrivateKey(), h)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = verifyCanResolve(resolver, identity.ID().Pretty(), h)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func verifyCanResolve(r Resolver, name string, exp path.Path) error {
|
||||
res, err := r.Resolve(context.Background(), name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res != exp {
|
||||
return errors.New("got back wrong record")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -1,148 +0,0 @@
|
||||
package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
ipns "github.com/ipfs/go-ipns"
|
||||
pb "github.com/ipfs/go-ipns/pb"
|
||||
logging "github.com/ipfs/go-log"
|
||||
path "github.com/ipfs/go-path"
|
||||
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
routing "github.com/libp2p/go-libp2p-core/routing"
|
||||
dht "github.com/libp2p/go-libp2p-kad-dht"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
var log = logging.Logger("namesys")
|
||||
|
||||
// IpnsResolver implements NSResolver for the main IPFS SFS-like naming
|
||||
type IpnsResolver struct {
|
||||
routing routing.ValueStore
|
||||
}
|
||||
|
||||
// NewIpnsResolver constructs a name resolver using the IPFS Routing system
|
||||
// to implement SFS-like naming on top.
|
||||
func NewIpnsResolver(route routing.ValueStore) *IpnsResolver {
|
||||
if route == nil {
|
||||
panic("attempt to create resolver with nil routing system")
|
||||
}
|
||||
return &IpnsResolver{
|
||||
routing: route,
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve implements Resolver.
|
||||
func (r *IpnsResolver) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) {
|
||||
return resolve(ctx, r, name, opts.ProcessOpts(options))
|
||||
}
|
||||
|
||||
// ResolveAsync implements Resolver.
|
||||
func (r *IpnsResolver) ResolveAsync(ctx context.Context, name string, options ...opts.ResolveOpt) <-chan Result {
|
||||
return resolveAsync(ctx, r, name, opts.ProcessOpts(options))
|
||||
}
|
||||
|
||||
// resolveOnce implements resolver. Uses the IPFS routing system to
|
||||
// resolve SFS-like names.
|
||||
func (r *IpnsResolver) resolveOnceAsync(ctx context.Context, name string, options opts.ResolveOpts) <-chan onceResult {
|
||||
out := make(chan onceResult, 1)
|
||||
log.Debugf("RoutingResolver resolving %s", name)
|
||||
cancel := func() {}
|
||||
|
||||
if options.DhtTimeout != 0 {
|
||||
// Resolution must complete within the timeout
|
||||
ctx, cancel = context.WithTimeout(ctx, options.DhtTimeout)
|
||||
}
|
||||
|
||||
name = strings.TrimPrefix(name, "/ipns/")
|
||||
|
||||
pid, err := peer.Decode(name)
|
||||
if err != nil {
|
||||
log.Debugf("RoutingResolver: could not convert public key hash %s to peer ID: %s\n", name, err)
|
||||
out <- onceResult{err: err}
|
||||
close(out)
|
||||
cancel()
|
||||
return out
|
||||
}
|
||||
|
||||
// Use the routing system to get the name.
|
||||
// Note that the DHT will call the ipns validator when retrieving
|
||||
// the value, which in turn verifies the ipns record signature
|
||||
ipnsKey := ipns.RecordKey(pid)
|
||||
|
||||
vals, err := r.routing.SearchValue(ctx, ipnsKey, dht.Quorum(int(options.DhtRecordCount)))
|
||||
if err != nil {
|
||||
log.Debugf("RoutingResolver: dht get for name %s failed: %s", name, err)
|
||||
out <- onceResult{err: err}
|
||||
close(out)
|
||||
cancel()
|
||||
return out
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer cancel()
|
||||
defer close(out)
|
||||
for {
|
||||
select {
|
||||
case val, ok := <-vals:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
entry := new(pb.IpnsEntry)
|
||||
err = proto.Unmarshal(val, entry)
|
||||
if err != nil {
|
||||
log.Debugf("RoutingResolver: could not unmarshal value for name %s: %s", name, err)
|
||||
emitOnceResult(ctx, out, onceResult{err: err})
|
||||
return
|
||||
}
|
||||
|
||||
var p path.Path
|
||||
// check for old style record:
|
||||
if valh, err := mh.Cast(entry.GetValue()); err == nil {
|
||||
// Its an old style multihash record
|
||||
log.Debugf("encountered CIDv0 ipns entry: %s", valh)
|
||||
p = path.FromCid(cid.NewCidV0(valh))
|
||||
} else {
|
||||
// Not a multihash, probably a new style record
|
||||
p, err = path.ParsePath(string(entry.GetValue()))
|
||||
if err != nil {
|
||||
emitOnceResult(ctx, out, onceResult{err: err})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ttl := DefaultResolverCacheTTL
|
||||
if entry.Ttl != nil {
|
||||
ttl = time.Duration(*entry.Ttl)
|
||||
}
|
||||
switch eol, err := ipns.GetEOL(entry); err {
|
||||
case ipns.ErrUnrecognizedValidity:
|
||||
// No EOL.
|
||||
case nil:
|
||||
ttEol := time.Until(eol)
|
||||
if ttEol < 0 {
|
||||
// It *was* valid when we first resolved it.
|
||||
ttl = 0
|
||||
} else if ttEol < ttl {
|
||||
ttl = ttEol
|
||||
}
|
||||
default:
|
||||
log.Errorf("encountered error when parsing EOL: %s", err)
|
||||
emitOnceResult(ctx, out, onceResult{err: err})
|
||||
return
|
||||
}
|
||||
|
||||
emitOnceResult(ctx, out, onceResult{value: p, ttl: ttl})
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
@ -11,7 +11,7 @@ import (
|
||||
"sync"
|
||||
|
||||
filestore "github.com/ipfs/go-filestore"
|
||||
keystore "github.com/ipfs/go-ipfs/keystore"
|
||||
keystore "github.com/ipfs/go-ipfs-keystore"
|
||||
repo "github.com/ipfs/go-ipfs/repo"
|
||||
"github.com/ipfs/go-ipfs/repo/common"
|
||||
mfsr "github.com/ipfs/go-ipfs/repo/fsrepo/migrations"
|
||||
|
||||
@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
|
||||
filestore "github.com/ipfs/go-filestore"
|
||||
keystore "github.com/ipfs/go-ipfs/keystore"
|
||||
keystore "github.com/ipfs/go-ipfs-keystore"
|
||||
|
||||
config "github.com/ipfs/go-ipfs-config"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
|
||||
@ -5,7 +5,7 @@ import (
|
||||
"io"
|
||||
|
||||
filestore "github.com/ipfs/go-filestore"
|
||||
keystore "github.com/ipfs/go-ipfs/keystore"
|
||||
keystore "github.com/ipfs/go-ipfs-keystore"
|
||||
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
config "github.com/ipfs/go-ipfs-config"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user