private/server,satellite/contact,misc: use new storj/common noise helpers
this change uses the new storj/common noise helpers, which: * add a security fix (require an expected node id for validating noise key attestations) * stops doing an unnecessary order signature validation (it's already been done inside of PutPiece) * removes some duplicate code Change-Id: I5e67a08ff216cd9c5b0b82e40b4d9de664b6b0fc
This commit is contained in:
parent
dcebcf770d
commit
522aed083d
6
go.mod
6
go.mod
@ -9,7 +9,6 @@ require (
|
|||||||
github.com/calebcase/tmpfile v1.0.3
|
github.com/calebcase/tmpfile v1.0.3
|
||||||
github.com/cheggaaa/pb/v3 v3.0.5
|
github.com/cheggaaa/pb/v3 v3.0.5
|
||||||
github.com/fatih/color v1.9.0
|
github.com/fatih/color v1.9.0
|
||||||
github.com/flynn/noise v1.0.0
|
|
||||||
github.com/go-oauth2/oauth2/v4 v4.4.2
|
github.com/go-oauth2/oauth2/v4 v4.4.2
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
github.com/gogo/protobuf v1.3.2
|
github.com/gogo/protobuf v1.3.2
|
||||||
@ -39,7 +38,6 @@ require (
|
|||||||
github.com/stripe/stripe-go/v72 v72.51.0
|
github.com/stripe/stripe-go/v72 v72.51.0
|
||||||
github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3
|
github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3
|
||||||
github.com/zeebo/assert v1.3.1
|
github.com/zeebo/assert v1.3.1
|
||||||
github.com/zeebo/blake3 v0.2.3
|
|
||||||
github.com/zeebo/clingy v0.0.0-20220926155919-717640cb8ccd
|
github.com/zeebo/clingy v0.0.0-20220926155919-717640cb8ccd
|
||||||
github.com/zeebo/errs v1.3.0
|
github.com/zeebo/errs v1.3.0
|
||||||
github.com/zeebo/ini v0.0.0-20210331155437-86af75b4f524
|
github.com/zeebo/ini v0.0.0-20210331155437-86af75b4f524
|
||||||
@ -55,7 +53,7 @@ require (
|
|||||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
|
||||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0
|
gopkg.in/segmentio/analytics-go.v3 v3.1.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
storj.io/common v0.0.0-20230203132517-db6195f39c0d
|
storj.io/common v0.0.0-20230207140859-1c86f3de8c15
|
||||||
storj.io/drpc v0.0.32
|
storj.io/drpc v0.0.32
|
||||||
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41
|
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41
|
||||||
storj.io/private v0.0.0-20230123202745-d3e63b336444
|
storj.io/private v0.0.0-20230123202745-d3e63b336444
|
||||||
@ -74,6 +72,7 @@ require (
|
|||||||
github.com/cloudfoundry/gosigar v1.1.0 // indirect
|
github.com/cloudfoundry/gosigar v1.1.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/flynn/noise v1.0.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
github.com/golang-jwt/jwt v3.2.1+incompatible // indirect
|
github.com/golang-jwt/jwt v3.2.1+incompatible // indirect
|
||||||
@ -116,6 +115,7 @@ require (
|
|||||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
|
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
|
||||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect
|
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect
|
||||||
github.com/zeebo/admission/v3 v3.0.3 // indirect
|
github.com/zeebo/admission/v3 v3.0.3 // indirect
|
||||||
|
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||||
github.com/zeebo/errs/v2 v2.0.3 // indirect
|
github.com/zeebo/errs/v2 v2.0.3 // indirect
|
||||||
github.com/zeebo/float16 v0.1.0 // indirect
|
github.com/zeebo/float16 v0.1.0 // indirect
|
||||||
github.com/zeebo/incenc v0.0.0-20180505221441-0d92902eec54 // indirect
|
github.com/zeebo/incenc v0.0.0-20180505221441-0d92902eec54 // indirect
|
||||||
|
4
go.sum
4
go.sum
@ -960,8 +960,8 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
|
|||||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||||
storj.io/common v0.0.0-20220719163320-cd2ef8e1b9b0/go.mod h1:mCYV6Ud5+cdbuaxdPD5Zht/HYaIn0sffnnws9ErkrMQ=
|
storj.io/common v0.0.0-20220719163320-cd2ef8e1b9b0/go.mod h1:mCYV6Ud5+cdbuaxdPD5Zht/HYaIn0sffnnws9ErkrMQ=
|
||||||
storj.io/common v0.0.0-20230203132517-db6195f39c0d h1:YXUKpQExPezrMlUn05Zu1ydLGYDwcU1eyMkxDgsfwI0=
|
storj.io/common v0.0.0-20230207140859-1c86f3de8c15 h1:zxniPpRV4V0e4UwYkJgLHik1ZeslbXt136Y04ms1G1s=
|
||||||
storj.io/common v0.0.0-20230203132517-db6195f39c0d/go.mod h1:oNPn8QmwPRXSGWwHoMFLGi9c+vOYbGmRYQQ/IhZi4lM=
|
storj.io/common v0.0.0-20230207140859-1c86f3de8c15/go.mod h1:i5P+zXit50yn4GUHvjET+rJX/uB9S56EISpyaTOVkrE=
|
||||||
storj.io/drpc v0.0.32 h1:5p5ZwsK/VOgapaCu+oxaPVwO6UwIs+iwdMiD50+R4PI=
|
storj.io/drpc v0.0.32 h1:5p5ZwsK/VOgapaCu+oxaPVwO6UwIs+iwdMiD50+R4PI=
|
||||||
storj.io/drpc v0.0.32/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
|
storj.io/drpc v0.0.32/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
|
||||||
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41 h1:SVuEocEhZfFc13J1AmlVLitdGXTVrvmbzN4Z9C9Ms40=
|
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41 h1:SVuEocEhZfFc13J1AmlVLitdGXTVrvmbzN4Z9C9Ms40=
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
// Copyright (C) 2022 Storj Labs, Inc.
|
|
||||||
// See LICENSE for copying information.
|
|
||||||
|
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/subtle"
|
|
||||||
"encoding/binary"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/flynn/noise"
|
|
||||||
|
|
||||||
"storj.io/common/identity"
|
|
||||||
"storj.io/common/pb"
|
|
||||||
"storj.io/common/signing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NoiseHeader is the drpcmigrate.Header prefix for DRPC over Noise.
|
|
||||||
const NoiseHeader = "DRPC!N!1"
|
|
||||||
|
|
||||||
// defaultNoiseProto is the protobuf enum value that specifies what noise
|
|
||||||
// protocol is in use.
|
|
||||||
// defaultNoiseInfo and defaultNoiseConfig should be changed together.
|
|
||||||
var defaultNoiseProto = pb.NoiseProtocol_NOISE_IK_25519_CHACHAPOLY_BLAKE2B
|
|
||||||
|
|
||||||
// defaultNoiseConfig returns the structure that tells this node what Noise
|
|
||||||
// settings to use.
|
|
||||||
// defaultNoiseProto and defaultNoiseConfig should be changed together.
|
|
||||||
func defaultNoiseConfig() noise.Config {
|
|
||||||
return noise.Config{
|
|
||||||
CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashBLAKE2b),
|
|
||||||
Pattern: noise.HandshakeIK,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func signableNoisePublicKey(ts time.Time, key []byte) []byte {
|
|
||||||
var buf [8]byte
|
|
||||||
tsnano := ts.UnixNano()
|
|
||||||
if tsnano < 0 {
|
|
||||||
tsnano = 0
|
|
||||||
}
|
|
||||||
binary.BigEndian.PutUint64(buf[:], uint64(tsnano))
|
|
||||||
return append(buf[:], key...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateNoiseKeyAttestation will sign a given Noise public key using the
|
|
||||||
// Node's leaf key and certificate chain, generating a pb.NoiseKeyAttestation.
|
|
||||||
func GenerateNoiseKeyAttestation(ctx context.Context, ident *identity.FullIdentity, info *pb.NoiseInfo) (_ *pb.NoiseKeyAttestation, err error) {
|
|
||||||
defer mon.Task()(&ctx)(&err)
|
|
||||||
ts := time.Now()
|
|
||||||
signature, err := signing.SignerFromFullIdentity(ident).HashAndSign(ctx,
|
|
||||||
append([]byte("noise-key-attestation-v1:"), signableNoisePublicKey(ts, info.PublicKey)...))
|
|
||||||
if err != nil {
|
|
||||||
return nil, Error.Wrap(err)
|
|
||||||
}
|
|
||||||
return &pb.NoiseKeyAttestation{
|
|
||||||
NodeId: ident.ID,
|
|
||||||
NodeCertchain: identity.EncodePeerIdentity(ident.PeerIdentity()),
|
|
||||||
NoiseProto: info.Proto,
|
|
||||||
NoisePublicKey: info.PublicKey,
|
|
||||||
Timestamp: ts,
|
|
||||||
Signature: signature,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateNoiseKeyAttestation will confirm that a provided
|
|
||||||
// *pb.NoiseKeyAttestation was signed correctly.
|
|
||||||
func ValidateNoiseKeyAttestation(ctx context.Context, attestation *pb.NoiseKeyAttestation) (err error) {
|
|
||||||
defer mon.Task()(&ctx)(&err)
|
|
||||||
peer, err := identity.DecodePeerIdentity(ctx, attestation.NodeCertchain)
|
|
||||||
if err != nil {
|
|
||||||
return Error.Wrap(err)
|
|
||||||
}
|
|
||||||
err = peer.Leaf.CheckSignatureFrom(peer.CA)
|
|
||||||
if err != nil {
|
|
||||||
return Error.New("certificate chain invalid: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if subtle.ConstantTimeCompare(peer.ID.Bytes(), attestation.NodeId.Bytes()) != 1 {
|
|
||||||
return Error.New("node id mismatch")
|
|
||||||
}
|
|
||||||
signee := signing.SigneeFromPeerIdentity(peer)
|
|
||||||
unsigned := signableNoisePublicKey(attestation.Timestamp, attestation.NoisePublicKey)
|
|
||||||
err = signee.HashAndVerifySignature(ctx,
|
|
||||||
append([]byte("noise-key-attestation-v1:"), unsigned...),
|
|
||||||
attestation.Signature)
|
|
||||||
return Error.Wrap(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateNoiseSessionAttestation will sign a given Noise session handshake
|
|
||||||
// hash using the Node's leaf key and certificate chain, generating a
|
|
||||||
// pb.NoiseSessionAttestation.
|
|
||||||
func GenerateNoiseSessionAttestation(ctx context.Context, ident *identity.FullIdentity, handshakeHash []byte) (_ *pb.NoiseSessionAttestation, err error) {
|
|
||||||
defer mon.Task()(&ctx)(&err)
|
|
||||||
signature, err := signing.SignerFromFullIdentity(ident).HashAndSign(ctx,
|
|
||||||
append([]byte("noise-session-attestation-v1:"), handshakeHash...))
|
|
||||||
if err != nil {
|
|
||||||
return nil, Error.Wrap(err)
|
|
||||||
}
|
|
||||||
return &pb.NoiseSessionAttestation{
|
|
||||||
NodeId: ident.ID,
|
|
||||||
NodeCertchain: identity.EncodePeerIdentity(ident.PeerIdentity()),
|
|
||||||
NoiseHandshakeHash: handshakeHash,
|
|
||||||
Signature: signature,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateNoiseSessionAttestation will confirm that a provided
|
|
||||||
// *pb.NoiseSessionAttestation was signed correctly.
|
|
||||||
func ValidateNoiseSessionAttestation(ctx context.Context, attestation *pb.NoiseSessionAttestation) (err error) {
|
|
||||||
defer mon.Task()(&ctx)(&err)
|
|
||||||
peer, err := identity.DecodePeerIdentity(ctx, attestation.NodeCertchain)
|
|
||||||
if err != nil {
|
|
||||||
return Error.Wrap(err)
|
|
||||||
}
|
|
||||||
err = peer.Leaf.CheckSignatureFrom(peer.CA)
|
|
||||||
if err != nil {
|
|
||||||
return Error.New("certificate chain invalid: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if subtle.ConstantTimeCompare(peer.ID.Bytes(), attestation.NodeId.Bytes()) != 1 {
|
|
||||||
return Error.New("node id mismatch")
|
|
||||||
}
|
|
||||||
signee := signing.SigneeFromPeerIdentity(peer)
|
|
||||||
err = signee.HashAndVerifySignature(ctx,
|
|
||||||
append([]byte("noise-session-attestation-v1:"), attestation.NoiseHandshakeHash...),
|
|
||||||
attestation.Signature)
|
|
||||||
return Error.Wrap(err)
|
|
||||||
|
|
||||||
}
|
|
@ -1,117 +0,0 @@
|
|||||||
// Copyright (C) 2023 Storj Labs, Inc.
|
|
||||||
// See LICENSE for copying information.
|
|
||||||
|
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"storj.io/common/identity"
|
|
||||||
"storj.io/common/pb"
|
|
||||||
"storj.io/common/storj"
|
|
||||||
"storj.io/common/testcontext"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNoiseKeyAttestation(t *testing.T) {
|
|
||||||
ctx := testcontext.New(t)
|
|
||||||
ident, err := identity.NewFullIdentity(ctx, identity.NewCAOptions{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
ident2, err := identity.NewFullIdentity(ctx, identity.NewCAOptions{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
ident3, err := identity.NewFullIdentity(ctx, identity.NewCAOptions{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
noiseCfg, err := generateNoiseConf(ident)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
attestation, err := GenerateNoiseKeyAttestation(ctx, ident, &pb.NoiseInfo{
|
|
||||||
Proto: defaultNoiseProto,
|
|
||||||
PublicKey: noiseCfg.StaticKeypair.Public,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.NoError(t, ValidateNoiseKeyAttestation(ctx, attestation))
|
|
||||||
|
|
||||||
badAttestation1 := *attestation
|
|
||||||
badAttestation1.NodeId, err = storj.NodeIDFromString("121RTSDpyNZVcEU84Ticf2L1ntiuUimbWgfATz21tuvgk3vzoA6")
|
|
||||||
require.NoError(t, err)
|
|
||||||
err = ValidateNoiseKeyAttestation(ctx, &badAttestation1)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), "node id mismatch")
|
|
||||||
|
|
||||||
badAttestation2 := *attestation
|
|
||||||
badAttestation2.NoisePublicKey = badAttestation2.NoisePublicKey[:len(badAttestation2.NoisePublicKey)-1]
|
|
||||||
err = ValidateNoiseKeyAttestation(ctx, &badAttestation2)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), "signature is not valid")
|
|
||||||
|
|
||||||
badAttestation3 := *attestation
|
|
||||||
badAttestation3.Timestamp = time.Now()
|
|
||||||
err = ValidateNoiseKeyAttestation(ctx, &badAttestation3)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), "signature is not valid")
|
|
||||||
|
|
||||||
ident2.CA = ident.CA
|
|
||||||
badAttestation4 := *attestation
|
|
||||||
badAttestation4.NodeCertchain = identity.EncodePeerIdentity(ident2.PeerIdentity())
|
|
||||||
err = ValidateNoiseKeyAttestation(ctx, &badAttestation4)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), "certificate chain invalid")
|
|
||||||
|
|
||||||
ident3.Leaf = ident.Leaf
|
|
||||||
badAttestation5 := *attestation
|
|
||||||
badAttestation5.NodeCertchain = identity.EncodePeerIdentity(ident3.PeerIdentity())
|
|
||||||
err = ValidateNoiseKeyAttestation(ctx, &badAttestation5)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), "certificate chain invalid")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoiseSessionAttestation(t *testing.T) {
|
|
||||||
ctx := testcontext.New(t)
|
|
||||||
ident, err := identity.NewFullIdentity(ctx, identity.NewCAOptions{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
ident2, err := identity.NewFullIdentity(ctx, identity.NewCAOptions{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
ident3, err := identity.NewFullIdentity(ctx, identity.NewCAOptions{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
var hash [32]byte
|
|
||||||
_, err = rand.Read(hash[:])
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
attestation, err := GenerateNoiseSessionAttestation(ctx, ident, hash[:])
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.NoError(t, ValidateNoiseSessionAttestation(ctx, attestation))
|
|
||||||
|
|
||||||
badAttestation1 := *attestation
|
|
||||||
badAttestation1.NodeId, err = storj.NodeIDFromString("121RTSDpyNZVcEU84Ticf2L1ntiuUimbWgfATz21tuvgk3vzoA6")
|
|
||||||
require.NoError(t, err)
|
|
||||||
err = ValidateNoiseSessionAttestation(ctx, &badAttestation1)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), "node id mismatch")
|
|
||||||
|
|
||||||
badAttestation2 := *attestation
|
|
||||||
badAttestation2.NoiseHandshakeHash = badAttestation2.NoiseHandshakeHash[:len(badAttestation2.NoiseHandshakeHash)-1]
|
|
||||||
err = ValidateNoiseSessionAttestation(ctx, &badAttestation2)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), "signature is not valid")
|
|
||||||
|
|
||||||
ident2.CA = ident.CA
|
|
||||||
badAttestation3 := *attestation
|
|
||||||
badAttestation3.NodeCertchain = identity.EncodePeerIdentity(ident2.PeerIdentity())
|
|
||||||
err = ValidateNoiseSessionAttestation(ctx, &badAttestation3)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), "certificate chain invalid")
|
|
||||||
|
|
||||||
ident3.Leaf = ident.Leaf
|
|
||||||
badAttestation4 := *attestation
|
|
||||||
badAttestation4.NodeCertchain = identity.EncodePeerIdentity(ident3.PeerIdentity())
|
|
||||||
err = ValidateNoiseSessionAttestation(ctx, &badAttestation4)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), "certificate chain invalid")
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
// Copyright (C) 2023 Storj Labs, Inc.
|
|
||||||
// See LICENSE for copying information.
|
|
||||||
|
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zeebo/errs"
|
|
||||||
|
|
||||||
"storj.io/common/pb"
|
|
||||||
"storj.io/drpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type replayRouter struct {
|
|
||||||
replaySafe, all drpc.Mux
|
|
||||||
}
|
|
||||||
|
|
||||||
func newReplayRouter(replaySafe, all drpc.Mux) drpc.Mux {
|
|
||||||
return &replayRouter{
|
|
||||||
replaySafe: replaySafe,
|
|
||||||
all: all,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register implements drpc.Mux.
|
|
||||||
func (r *replayRouter) Register(srv interface{}, desc drpc.Description) error {
|
|
||||||
allErr := r.all.Register(srv, desc)
|
|
||||||
switch desc.(type) {
|
|
||||||
case pb.DRPCPiecestoreDescription:
|
|
||||||
return errs.Combine(allErr, r.replaySafe.Register(srv, replaySafePiecestore{}))
|
|
||||||
default:
|
|
||||||
return allErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type replaySafePiecestore struct{}
|
|
||||||
|
|
||||||
func (replaySafePiecestore) NumMethods() int { return 2 }
|
|
||||||
|
|
||||||
func (replaySafePiecestore) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) {
|
|
||||||
switch n {
|
|
||||||
case 0:
|
|
||||||
rpc, enc, receiver, method, ok := (pb.DRPCPiecestoreDescription{}).Method(0)
|
|
||||||
return rpc, enc, receiver, method, ok && rpc == "/piecestore.Piecestore/Upload"
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
rpc, enc, receiver, method, ok := (pb.DRPCPiecestoreDescription{}).Method(1)
|
|
||||||
return rpc, enc, receiver, method, ok && rpc == "/piecestore.Piecestore/Download"
|
|
||||||
default:
|
|
||||||
return "", nil, nil, nil, false
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,9 +6,7 @@ package server
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -16,9 +14,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/flynn/noise"
|
|
||||||
"github.com/jtolio/noiseconn"
|
"github.com/jtolio/noiseconn"
|
||||||
"github.com/zeebo/blake3"
|
|
||||||
"github.com/zeebo/errs"
|
"github.com/zeebo/errs"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
@ -29,6 +25,7 @@ import (
|
|||||||
"storj.io/common/pb"
|
"storj.io/common/pb"
|
||||||
"storj.io/common/peertls/tlsopts"
|
"storj.io/common/peertls/tlsopts"
|
||||||
"storj.io/common/rpc"
|
"storj.io/common/rpc"
|
||||||
|
"storj.io/common/rpc/noise"
|
||||||
"storj.io/common/rpc/quic"
|
"storj.io/common/rpc/quic"
|
||||||
"storj.io/common/rpc/rpctracing"
|
"storj.io/common/rpc/rpctracing"
|
||||||
"storj.io/drpc"
|
"storj.io/drpc"
|
||||||
@ -79,36 +76,10 @@ type Server struct {
|
|||||||
done chan struct{}
|
done chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func identityBasedEntropy(context string, ident *identity.FullIdentity) (io.Reader, error) {
|
|
||||||
h := blake3.NewDeriveKey(context)
|
|
||||||
|
|
||||||
serialized, err := x509.MarshalPKCS8PrivateKey(ident.Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, Error.Wrap(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = h.Write(serialized)
|
|
||||||
return h.Digest(), Error.Wrap(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateNoiseConf(ident *identity.FullIdentity) (noise.Config, error) {
|
|
||||||
noiseConf := defaultNoiseConfig()
|
|
||||||
noiseConf.Initiator = false
|
|
||||||
entropy, err := identityBasedEntropy("noise key", ident)
|
|
||||||
if err != nil {
|
|
||||||
return noise.Config{}, err
|
|
||||||
}
|
|
||||||
noiseConf.StaticKeypair, err = noiseConf.CipherSuite.GenerateKeypair(entropy)
|
|
||||||
if err != nil {
|
|
||||||
return noise.Config{}, Error.Wrap(err)
|
|
||||||
}
|
|
||||||
return noiseConf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a Server out of an Identity, a net.Listener,
|
// New creates a Server out of an Identity, a net.Listener,
|
||||||
// and interceptors.
|
// and interceptors.
|
||||||
func New(log *zap.Logger, tlsOptions *tlsopts.Options, config Config) (_ *Server, err error) {
|
func New(log *zap.Logger, tlsOptions *tlsopts.Options, config Config) (_ *Server, err error) {
|
||||||
noiseConf, err := generateNoiseConf(tlsOptions.Ident)
|
noiseConf, err := noise.GenerateServerConf(noise.DefaultProto, tlsOptions.Ident)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -208,12 +179,16 @@ func (p *Server) Addr() net.Addr { return p.addr }
|
|||||||
// PrivateAddr returns the server's private listener address.
|
// PrivateAddr returns the server's private listener address.
|
||||||
func (p *Server) PrivateAddr() net.Addr { return p.privateTCPListener.Addr() }
|
func (p *Server) PrivateAddr() net.Addr { return p.privateTCPListener.Addr() }
|
||||||
|
|
||||||
// DRPC returns the server's DRPC mux for registration purposes.
|
// DRPC returns the server's DRPC mux that supports all endpoints for
|
||||||
|
// registration purposes.
|
||||||
func (p *Server) DRPC() drpc.Mux {
|
func (p *Server) DRPC() drpc.Mux {
|
||||||
return newReplayRouter(
|
return p.publicEndpointsAll.mux
|
||||||
p.publicEndpointsReplaySafe.mux,
|
}
|
||||||
p.publicEndpointsAll.mux,
|
|
||||||
)
|
// ReplaySafeDRPC returns the server's DRPC mux that supports replay safe
|
||||||
|
// endpoints for registration purposes.
|
||||||
|
func (p *Server) ReplaySafeDRPC() drpc.Mux {
|
||||||
|
return p.publicEndpointsReplaySafe.mux
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrivateDRPC returns the server's DRPC mux for registration purposes.
|
// PrivateDRPC returns the server's DRPC mux for registration purposes.
|
||||||
@ -222,19 +197,14 @@ func (p *Server) PrivateDRPC() drpc.Mux { return p.privateEndpoints.mux }
|
|||||||
// IsQUICEnabled checks if QUIC is enabled by config and udp port is open.
|
// IsQUICEnabled checks if QUIC is enabled by config and udp port is open.
|
||||||
func (p *Server) IsQUICEnabled() bool { return !p.config.DisableQUIC && p.publicUDPConn != nil }
|
func (p *Server) IsQUICEnabled() bool { return !p.config.DisableQUIC && p.publicUDPConn != nil }
|
||||||
|
|
||||||
// NoiseInfo returns the noise configuration for this server. This includes the
|
|
||||||
// keypair in use.
|
|
||||||
func (p *Server) NoiseInfo() *pb.NoiseInfo {
|
|
||||||
return &pb.NoiseInfo{
|
|
||||||
Proto: defaultNoiseProto,
|
|
||||||
PublicKey: p.noiseConf.StaticKeypair.Public,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NoiseKeyAttestation returns the noise key attestation for this server.
|
// NoiseKeyAttestation returns the noise key attestation for this server.
|
||||||
func (p *Server) NoiseKeyAttestation(ctx context.Context) (_ *pb.NoiseKeyAttestation, err error) {
|
func (p *Server) NoiseKeyAttestation(ctx context.Context) (_ *pb.NoiseKeyAttestation, err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
return GenerateNoiseKeyAttestation(ctx, p.tlsOptions.Ident, p.NoiseInfo())
|
info, err := noise.ConfigToInfo(p.noiseConf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return noise.GenerateKeyAttestation(ctx, p.tlsOptions.Ident, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close shuts down the server.
|
// Close shuts down the server.
|
||||||
@ -328,7 +298,7 @@ func (p *Server) Run(ctx context.Context) (err error) {
|
|||||||
if p.publicTCPListener != nil {
|
if p.publicTCPListener != nil {
|
||||||
publicLMux := drpcmigrate.NewListenMux(p.publicTCPListener, len(drpcmigrate.DRPCHeader))
|
publicLMux := drpcmigrate.NewListenMux(p.publicTCPListener, len(drpcmigrate.DRPCHeader))
|
||||||
publicTLSDRPCListener = tls.NewListener(publicLMux.Route(drpcmigrate.DRPCHeader), p.tlsOptions.ServerTLSConfig())
|
publicTLSDRPCListener = tls.NewListener(publicLMux.Route(drpcmigrate.DRPCHeader), p.tlsOptions.ServerTLSConfig())
|
||||||
publicNoiseDRPCListener = noiseconn.NewListener(publicLMux.Route(NoiseHeader), p.noiseConf)
|
publicNoiseDRPCListener = noiseconn.NewListener(publicLMux.Route(noise.Header), p.noiseConf)
|
||||||
if p.publicHTTP != nil {
|
if p.publicHTTP != nil {
|
||||||
publicHTTPListener = NewPrefixedListener([]byte("GET / HT"), publicLMux.Route("GET / HT"))
|
publicHTTPListener = NewPrefixedListener([]byte("GET / HT"), publicLMux.Route("GET / HT"))
|
||||||
}
|
}
|
||||||
|
@ -200,6 +200,8 @@ func TestDownloadFromUnresponsiveNode(t *testing.T) {
|
|||||||
|
|
||||||
err = pb.DRPCRegisterPiecestore(server.DRPC(), &piecestoreMock{})
|
err = pb.DRPCRegisterPiecestore(server.DRPC(), &piecestoreMock{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
err = pb.DRPCRegisterReplaySafePiecestore(server.ReplaySafeDRPC(), &piecestoreMock{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
defer ctx.Check(server.Close)
|
defer ctx.Check(server.Close)
|
||||||
|
|
||||||
|
@ -14,11 +14,11 @@ import (
|
|||||||
|
|
||||||
"storj.io/common/identity"
|
"storj.io/common/identity"
|
||||||
"storj.io/common/pb"
|
"storj.io/common/pb"
|
||||||
|
"storj.io/common/rpc/noise"
|
||||||
"storj.io/common/rpc/rpcstatus"
|
"storj.io/common/rpc/rpcstatus"
|
||||||
"storj.io/common/storj"
|
"storj.io/common/storj"
|
||||||
"storj.io/drpc/drpcctx"
|
"storj.io/drpc/drpcctx"
|
||||||
"storj.io/storj/private/nodeoperator"
|
"storj.io/storj/private/nodeoperator"
|
||||||
"storj.io/storj/private/server"
|
|
||||||
"storj.io/storj/satellite/overlay"
|
"storj.io/storj/satellite/overlay"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ func (endpoint *Endpoint) CheckIn(ctx context.Context, req *pb.CheckInRequest) (
|
|||||||
|
|
||||||
var noiseInfo *pb.NoiseInfo
|
var noiseInfo *pb.NoiseInfo
|
||||||
if req.NoiseKeyAttestation != nil {
|
if req.NoiseKeyAttestation != nil {
|
||||||
if err := server.ValidateNoiseKeyAttestation(ctx, req.NoiseKeyAttestation); err == nil {
|
if err := noise.ValidateKeyAttestation(ctx, req.NoiseKeyAttestation, nodeID); err == nil {
|
||||||
noiseInfo = &pb.NoiseInfo{
|
noiseInfo = &pb.NoiseInfo{
|
||||||
Proto: req.NoiseKeyAttestation.NoiseProto,
|
Proto: req.NoiseKeyAttestation.NoiseProto,
|
||||||
PublicKey: req.NoiseKeyAttestation.NoisePublicKey,
|
PublicKey: req.NoiseKeyAttestation.NoisePublicKey,
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"storj.io/common/pb"
|
"storj.io/common/pb"
|
||||||
"storj.io/common/storj"
|
|
||||||
"storj.io/common/sync2"
|
"storj.io/common/sync2"
|
||||||
"storj.io/storj/satellite/nodeselection/uploadselection"
|
"storj.io/storj/satellite/nodeselection/uploadselection"
|
||||||
)
|
)
|
||||||
@ -122,18 +121,9 @@ func (cache *UploadSelectionCache) Size(ctx context.Context) (reputableNodeCount
|
|||||||
|
|
||||||
func convNodesToSelectedNodes(nodes []*uploadselection.Node) (xs []*SelectedNode) {
|
func convNodesToSelectedNodes(nodes []*uploadselection.Node) (xs []*SelectedNode) {
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
var noiseInfo *pb.NoiseInfo
|
|
||||||
if n.NoiseInfo.PublicKey != "" && n.NoiseInfo.Proto != storj.NoiseProto_Unset {
|
|
||||||
// TODO(jt): storj/common's NoiseInfoConvert or NodeFromNodeURL should
|
|
||||||
// handle this empty case.
|
|
||||||
noiseInfo = pb.NoiseInfoConvert(n.NoiseInfo)
|
|
||||||
}
|
|
||||||
xs = append(xs, &SelectedNode{
|
xs = append(xs, &SelectedNode{
|
||||||
ID: n.ID,
|
ID: n.ID,
|
||||||
Address: &pb.NodeAddress{
|
Address: pb.NodeFromNodeURL(n.NodeURL).Address,
|
||||||
Address: n.Address,
|
|
||||||
NoiseInfo: noiseInfo,
|
|
||||||
},
|
|
||||||
LastNet: n.LastNet,
|
LastNet: n.LastNet,
|
||||||
LastIPPort: n.LastIPPort,
|
LastIPPort: n.LastIPPort,
|
||||||
CountryCode: n.CountryCode,
|
CountryCode: n.CountryCode,
|
||||||
@ -144,17 +134,11 @@ func convNodesToSelectedNodes(nodes []*uploadselection.Node) (xs []*SelectedNode
|
|||||||
|
|
||||||
func convSelectedNodesToNodes(nodes []*SelectedNode) (xs []*uploadselection.Node) {
|
func convSelectedNodesToNodes(nodes []*SelectedNode) (xs []*uploadselection.Node) {
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
nodeurl := storj.NodeURL{
|
|
||||||
ID: n.ID,
|
|
||||||
Address: n.Address.Address,
|
|
||||||
}
|
|
||||||
if n.Address.NoiseInfo != nil {
|
|
||||||
// TODO(jt): storj/common's (*pb.Node).NodeURL() should
|
|
||||||
// handle this if statement.
|
|
||||||
nodeurl.NoiseInfo = n.Address.NoiseInfo.Convert()
|
|
||||||
}
|
|
||||||
xs = append(xs, &uploadselection.Node{
|
xs = append(xs, &uploadselection.Node{
|
||||||
NodeURL: nodeurl,
|
NodeURL: (&pb.Node{
|
||||||
|
Id: n.ID,
|
||||||
|
Address: n.Address,
|
||||||
|
}).NodeURL(),
|
||||||
LastNet: n.LastNet,
|
LastNet: n.LastNet,
|
||||||
LastIPPort: n.LastIPPort,
|
LastIPPort: n.LastIPPort,
|
||||||
CountryCode: n.CountryCode,
|
CountryCode: n.CountryCode,
|
||||||
|
@ -560,6 +560,9 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB, revocationDB exten
|
|||||||
if err := pb.DRPCRegisterPiecestore(peer.Server.DRPC(), peer.Storage2.Endpoint); err != nil {
|
if err := pb.DRPCRegisterPiecestore(peer.Server.DRPC(), peer.Storage2.Endpoint); err != nil {
|
||||||
return nil, errs.Combine(err, peer.Close())
|
return nil, errs.Combine(err, peer.Close())
|
||||||
}
|
}
|
||||||
|
if err := pb.DRPCRegisterReplaySafePiecestore(peer.Server.ReplaySafeDRPC(), peer.Storage2.Endpoint); err != nil {
|
||||||
|
return nil, errs.Combine(err, peer.Close())
|
||||||
|
}
|
||||||
|
|
||||||
// TODO workaround for custom timeout for order sending request (read/write)
|
// TODO workaround for custom timeout for order sending request (read/write)
|
||||||
sc := config.Server
|
sc := config.Server
|
||||||
|
@ -145,7 +145,7 @@ func (c *service) TransferPiece(ctx context.Context, satelliteID storj.NodeID, t
|
|||||||
putCtx, cancel := context.WithTimeout(ctx, maxTransferTime)
|
putCtx, cancel := context.WithTimeout(ctx, maxTransferTime)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
pieceHash, peerID, err := c.ecClient.PutPiece(putCtx, ctx, addrLimit, pk, reader)
|
pieceHash, _, err := c.ecClient.PutPiece(putCtx, ctx, addrLimit, pk, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if piecestore.ErrVerifyUntrusted.Has(err) {
|
if piecestore.ErrVerifyUntrusted.Has(err) {
|
||||||
return failMessage("failed hash verification", err, pb.TransferFailed_HASH_VERIFICATION)
|
return failMessage("failed hash verification", err, pb.TransferFailed_HASH_VERIFICATION)
|
||||||
@ -163,12 +163,6 @@ func (c *service) TransferPiece(ctx context.Context, satelliteID storj.NodeID, t
|
|||||||
return failMessage(msg, Error.New(msg), pb.TransferFailed_HASH_VERIFICATION)
|
return failMessage(msg, Error.New(msg), pb.TransferFailed_HASH_VERIFICATION)
|
||||||
}
|
}
|
||||||
|
|
||||||
signee := signing.SigneeFromPeerIdentity(peerID)
|
|
||||||
err = signing.VerifyPieceHashSignature(ctx, signee, pieceHash)
|
|
||||||
if err != nil {
|
|
||||||
return failMessage("invalid piece hash signature from new storagenode", err, pb.TransferFailed_HASH_VERIFICATION)
|
|
||||||
}
|
|
||||||
|
|
||||||
success := &pb.StorageNodeMessage{
|
success := &pb.StorageNodeMessage{
|
||||||
Message: &pb.StorageNodeMessage_Succeeded{
|
Message: &pb.StorageNodeMessage_Succeeded{
|
||||||
Succeeded: &pb.TransferSucceeded{
|
Succeeded: &pb.TransferSucceeded{
|
||||||
|
@ -10,7 +10,7 @@ require (
|
|||||||
github.com/zeebo/errs v1.3.0
|
github.com/zeebo/errs v1.3.0
|
||||||
go.uber.org/zap v1.21.0
|
go.uber.org/zap v1.21.0
|
||||||
golang.org/x/sync v0.1.0
|
golang.org/x/sync v0.1.0
|
||||||
storj.io/common v0.0.0-20230203132517-db6195f39c0d
|
storj.io/common v0.0.0-20230207140859-1c86f3de8c15
|
||||||
storj.io/private v0.0.0-20230123202745-d3e63b336444
|
storj.io/private v0.0.0-20230123202745-d3e63b336444
|
||||||
storj.io/storj v1.63.1
|
storj.io/storj v1.63.1
|
||||||
storj.io/storjscan v0.0.0-20220926140643-1623c3b391b0
|
storj.io/storjscan v0.0.0-20220926140643-1623c3b391b0
|
||||||
|
@ -1217,8 +1217,8 @@ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
|||||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||||
storj.io/common v0.0.0-20220719163320-cd2ef8e1b9b0/go.mod h1:mCYV6Ud5+cdbuaxdPD5Zht/HYaIn0sffnnws9ErkrMQ=
|
storj.io/common v0.0.0-20220719163320-cd2ef8e1b9b0/go.mod h1:mCYV6Ud5+cdbuaxdPD5Zht/HYaIn0sffnnws9ErkrMQ=
|
||||||
storj.io/common v0.0.0-20230203132517-db6195f39c0d h1:YXUKpQExPezrMlUn05Zu1ydLGYDwcU1eyMkxDgsfwI0=
|
storj.io/common v0.0.0-20230207140859-1c86f3de8c15 h1:zxniPpRV4V0e4UwYkJgLHik1ZeslbXt136Y04ms1G1s=
|
||||||
storj.io/common v0.0.0-20230203132517-db6195f39c0d/go.mod h1:oNPn8QmwPRXSGWwHoMFLGi9c+vOYbGmRYQQ/IhZi4lM=
|
storj.io/common v0.0.0-20230207140859-1c86f3de8c15/go.mod h1:i5P+zXit50yn4GUHvjET+rJX/uB9S56EISpyaTOVkrE=
|
||||||
storj.io/drpc v0.0.32 h1:5p5ZwsK/VOgapaCu+oxaPVwO6UwIs+iwdMiD50+R4PI=
|
storj.io/drpc v0.0.32 h1:5p5ZwsK/VOgapaCu+oxaPVwO6UwIs+iwdMiD50+R4PI=
|
||||||
storj.io/drpc v0.0.32/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
|
storj.io/drpc v0.0.32/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
|
||||||
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41 h1:SVuEocEhZfFc13J1AmlVLitdGXTVrvmbzN4Z9C9Ms40=
|
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41 h1:SVuEocEhZfFc13J1AmlVLitdGXTVrvmbzN4Z9C9Ms40=
|
||||||
|
@ -10,7 +10,7 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
go.uber.org/zap v1.23.0
|
go.uber.org/zap v1.23.0
|
||||||
storj.io/common v0.0.0-20230203132517-db6195f39c0d
|
storj.io/common v0.0.0-20230207140859-1c86f3de8c15
|
||||||
storj.io/gateway-mt v1.46.0
|
storj.io/gateway-mt v1.46.0
|
||||||
storj.io/private v0.0.0-20230123202745-d3e63b336444
|
storj.io/private v0.0.0-20230123202745-d3e63b336444
|
||||||
storj.io/storj v0.12.1-0.20221125175451-ef4b564b82f7
|
storj.io/storj v0.12.1-0.20221125175451-ef4b564b82f7
|
||||||
|
@ -1921,8 +1921,8 @@ sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1
|
|||||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||||
storj.io/common v0.0.0-20220719163320-cd2ef8e1b9b0/go.mod h1:mCYV6Ud5+cdbuaxdPD5Zht/HYaIn0sffnnws9ErkrMQ=
|
storj.io/common v0.0.0-20220719163320-cd2ef8e1b9b0/go.mod h1:mCYV6Ud5+cdbuaxdPD5Zht/HYaIn0sffnnws9ErkrMQ=
|
||||||
storj.io/common v0.0.0-20230203132517-db6195f39c0d h1:YXUKpQExPezrMlUn05Zu1ydLGYDwcU1eyMkxDgsfwI0=
|
storj.io/common v0.0.0-20230207140859-1c86f3de8c15 h1:zxniPpRV4V0e4UwYkJgLHik1ZeslbXt136Y04ms1G1s=
|
||||||
storj.io/common v0.0.0-20230203132517-db6195f39c0d/go.mod h1:oNPn8QmwPRXSGWwHoMFLGi9c+vOYbGmRYQQ/IhZi4lM=
|
storj.io/common v0.0.0-20230207140859-1c86f3de8c15/go.mod h1:i5P+zXit50yn4GUHvjET+rJX/uB9S56EISpyaTOVkrE=
|
||||||
storj.io/dotworld v0.0.0-20210324183515-0d11aeccd840 h1:oqMwoF6vaOrCe92SKRyr8cc2WSjLYAd8fjpAHA7rNqY=
|
storj.io/dotworld v0.0.0-20210324183515-0d11aeccd840 h1:oqMwoF6vaOrCe92SKRyr8cc2WSjLYAd8fjpAHA7rNqY=
|
||||||
storj.io/drpc v0.0.32 h1:5p5ZwsK/VOgapaCu+oxaPVwO6UwIs+iwdMiD50+R4PI=
|
storj.io/drpc v0.0.32 h1:5p5ZwsK/VOgapaCu+oxaPVwO6UwIs+iwdMiD50+R4PI=
|
||||||
storj.io/drpc v0.0.32/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
|
storj.io/drpc v0.0.32/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
|
||||||
|
Loading…
Reference in New Issue
Block a user