Make Bandwidth Agreements Secure / Trustable (#1117)

* Added cert chains and nodeid verification to bandwidth agreement
This commit is contained in:
Bill Thorp 2019-01-25 13:05:21 -05:00 committed by GitHub
parent 1385a2d6bd
commit 8ba4b61e59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 740 additions and 713 deletions

View File

@ -5,7 +5,6 @@ package tally_test
import (
"context"
"crypto/ecdsa"
"testing"
"time"
@ -18,6 +17,7 @@ import (
"storj.io/storj/pkg/accounting/tally"
"storj.io/storj/pkg/bwagreement"
"storj.io/storj/pkg/bwagreement/test"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/overlay/mocks"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/pointerdb"
@ -65,25 +65,23 @@ func TestQueryWithBw(t *testing.T) {
//get a private key
fiC, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err)
k, ok := fiC.Key.(*ecdsa.PrivateKey)
assert.True(t, ok)
makeBWA(ctx, t, bwDb, "1", k, pb.PayerBandwidthAllocation_PUT)
makeBWA(ctx, t, bwDb, "2", k, pb.PayerBandwidthAllocation_GET)
makeBWA(ctx, t, bwDb, "3", k, pb.PayerBandwidthAllocation_GET_AUDIT)
makeBWA(ctx, t, bwDb, "4", k, pb.PayerBandwidthAllocation_GET_REPAIR)
makeBWA(ctx, t, bwDb, "5", k, pb.PayerBandwidthAllocation_PUT_REPAIR)
makeBWA(ctx, t, bwDb, "1", fiC, pb.PayerBandwidthAllocation_PUT)
makeBWA(ctx, t, bwDb, "2", fiC, pb.PayerBandwidthAllocation_GET)
makeBWA(ctx, t, bwDb, "3", fiC, pb.PayerBandwidthAllocation_GET_AUDIT)
makeBWA(ctx, t, bwDb, "4", fiC, pb.PayerBandwidthAllocation_GET_REPAIR)
makeBWA(ctx, t, bwDb, "5", fiC, pb.PayerBandwidthAllocation_PUT_REPAIR)
//check the db
err = tally.QueryBW(ctx)
assert.NoError(t, err)
}
func makeBWA(ctx context.Context, t *testing.T, bwDb bwagreement.DB, serialNum string, k *ecdsa.PrivateKey, action pb.PayerBandwidthAllocation_Action) {
func makeBWA(ctx context.Context, t *testing.T, bwDb bwagreement.DB, serialNum string, fiC *identity.FullIdentity, action pb.PayerBandwidthAllocation_Action) {
//generate an agreement with the key
pba, err := test.GeneratePayerBandwidthAllocation(action, k, k, time.Hour)
pba, err := test.GeneratePayerBandwidthAllocation(action, fiC, fiC, time.Hour)
assert.NoError(t, err)
rba, err := test.GenerateRenterBandwidthAllocation(pba, teststorj.NodeIDFromString("StorageNodeID"), k)
rba, err := test.GenerateRenterBandwidthAllocation(pba, teststorj.NodeIDFromString("StorageNodeID"), fiC, 666)
assert.NoError(t, err)
//save to db
err = bwDb.CreateAgreement(ctx, serialNum, bwagreement.Agreement{Signature: rba.GetSignature(), Agreement: rba.GetData()})

85
pkg/auth/signedMessage.go Normal file
View File

@ -0,0 +1,85 @@
// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package auth
import (
"crypto/ecdsa"
"crypto/x509"
"github.com/gtank/cryptopasta"
"github.com/zeebo/errs"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/peertls"
"storj.io/storj/pkg/storj"
)
var (
//ECDSA indicates a key was not an ECDSA key
ECDSA = errs.New("Key is not ecdsa key")
//Sign indicates a failure during signing
Sign = errs.Class("Failed to sign message")
//Verify indicates a failure during signature validation
Verify = errs.Class("Failed to validate message signature")
//SigLen indicates an invalid signature length
SigLen = errs.Class("Invalid signature length")
//Serial indicates an invalid serial number length
Serial = errs.Class("Invalid SerialNumber")
//Expired indicates the agreement is expired
Expired = errs.Class("Agreement is expired")
//Signer indicates a public key / node id mismatch
Signer = errs.Class("Message public key did not match expected signer")
//BadID indicates a public key / node id mismatch
BadID = errs.Class("Node ID did not match expected id")
)
//VerifyMsg checks the crypto-related aspects of signed message
func VerifyMsg(sm pb.SignedMsg, signer storj.NodeID) error {
//no null fields
if ok, err := pb.MsgComplete(sm); !ok {
return err
}
certs := sm.GetCerts()
if len(certs) < 2 {
return Verify.New("Expected at least leaf and CA public keys")
}
//correct signature length
err := peertls.VerifyPeerFunc(peertls.VerifyPeerCertChains)(certs, nil)
if err != nil {
return Verify.Wrap(err)
}
leafPubKey, err := parseECDSA(certs[0])
if err != nil {
return err
}
caPubKey, err := parseECDSA(certs[1])
if err != nil {
return err
}
signatureLength := leafPubKey.Curve.Params().P.BitLen() / 8
if len(sm.GetSignature()) < signatureLength {
return SigLen.New("%s", sm.GetSignature())
}
// verify signature
if id, err := identity.NodeIDFromECDSAKey(caPubKey); err != nil || id != signer {
return Signer.New("%+v vs %+v", id, signer)
}
if ok := cryptopasta.Verify(sm.GetData(), sm.GetSignature(), leafPubKey); !ok {
return Verify.New("%+v", ok)
}
return nil
}
func parseECDSA(rawCert []byte) (*ecdsa.PublicKey, error) {
cert, err := x509.ParseCertificate(rawCert)
if err != nil {
return nil, Verify.Wrap(err)
}
ecdsa, ok := cert.PublicKey.(*ecdsa.PublicKey)
if !ok {
return nil, ECDSA
}
return ecdsa, nil
}

View File

@ -5,19 +5,16 @@ package bwagreement
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/x509"
"time"
"github.com/gogo/protobuf/proto"
"github.com/gtank/cryptopasta"
"github.com/zeebo/errs"
"go.uber.org/zap"
monkit "gopkg.in/spacemonkeygo/monkit.v2"
"storj.io/storj/pkg/auth"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/peertls"
"storj.io/storj/pkg/storj"
)
var (
@ -44,7 +41,7 @@ type DB interface {
// Server is an implementation of the pb.BandwidthServer interface
type Server struct {
db DB
pkey crypto.PublicKey
NodeID storj.NodeID
logger *zap.Logger
}
@ -57,129 +54,60 @@ type Agreement struct {
}
// NewServer creates instance of Server
func NewServer(db DB, logger *zap.Logger, pkey crypto.PublicKey) *Server {
func NewServer(db DB, logger *zap.Logger, nodeID storj.NodeID) *Server {
// TODO: reorder arguments, rename logger -> log
return &Server{
db: db,
logger: logger,
pkey: pkey,
}
return &Server{db: db, logger: logger, NodeID: nodeID}
}
// Close closes resources
func (s *Server) Close() error { return nil }
// BandwidthAgreements receives and stores bandwidth agreements from storage nodes
func (s *Server) BandwidthAgreements(ctx context.Context, ba *pb.RenterBandwidthAllocation) (reply *pb.AgreementsSummary, err error) {
func (s *Server) BandwidthAgreements(ctx context.Context, rba *pb.RenterBandwidthAllocation) (reply *pb.AgreementsSummary, err error) {
defer mon.Task()(&ctx)(&err)
s.logger.Debug("Received Agreement...")
reply = &pb.AgreementsSummary{
Status: pb.AgreementsSummary_REJECTED,
}
// storagenode signature is empty
if len(ba.GetSignature()) == 0 {
return reply, Error.New("Invalid Storage Node Signature length in the RenterBandwidthAllocation")
}
rbad := &pb.RenterBandwidthAllocation_Data{}
if err = proto.Unmarshal(ba.GetData(), rbad); err != nil {
return reply, Error.New("Failed to unmarshal RenterBandwidthAllocation: %+v", err)
}
pba := rbad.GetPayerAllocation()
pbad := &pb.PayerBandwidthAllocation_Data{}
if err := proto.Unmarshal(pba.GetData(), pbad); err != nil {
return reply, Error.New("Failed to unmarshal PayerBandwidthAllocation: %+v", err)
}
// satellite signature is empty
if len(pba.GetSignature()) == 0 {
return reply, Error.New("Invalid Satellite Signature length in the PayerBandwidthAllocation")
}
if len(pbad.SerialNumber) == 0 {
return reply, Error.New("Invalid SerialNumber in the PayerBandwidthAllocation")
}
if err = s.verifySignature(ctx, ba); err != nil {
rbad, pba, pbad, err := rba.Unpack()
if err != nil {
return reply, err
}
//verify message content
pi, err := identity.PeerIdentityFromContext(ctx)
if err != nil || rbad.StorageNodeId != pi.ID {
return reply, auth.BadID.New("Storage Node ID: %s vs %s", rbad.StorageNodeId, pi.ID)
}
//todo: use whitelist for uplinks?
if pbad.SatelliteId != s.NodeID {
return reply, pb.Payer.New("Satellite ID: %s vs %s", pbad.SatelliteId, s.NodeID)
}
serialNum := pbad.GetSerialNumber() + rbad.StorageNodeId.String()
// get and check expiration
if len(pbad.SerialNumber) == 0 {
return reply, pb.Payer.Wrap(pb.Missing.New("Serial"))
}
exp := time.Unix(pbad.GetExpirationUnixSec(), 0).UTC()
if exp.Before(time.Now().UTC()) {
return reply, Error.New("Bandwidth agreement is expired (%v)", exp)
return reply, pb.Payer.Wrap(auth.Expired.New("%v vs %v", exp, time.Now().UTC()))
}
//verify message crypto
if err := auth.VerifyMsg(rba, pbad.UplinkId); err != nil {
return reply, pb.Renter.Wrap(err)
}
if err := auth.VerifyMsg(pba, pbad.SatelliteId); err != nil {
return reply, pb.Payer.Wrap(err)
}
//save and return rersults
err = s.db.CreateAgreement(ctx, serialNum, Agreement{
Signature: ba.GetSignature(),
Agreement: ba.GetData(),
Signature: rba.GetSignature(),
Agreement: rba.GetData(),
ExpiresAt: exp,
})
if err != nil {
//todo: better classify transport errors (AgreementsSummary_FAIL) vs logical (AgreementsSummary_REJECTED)
return reply, Error.New("SerialNumber already exists in the PayerBandwidthAllocation")
return reply, pb.Payer.Wrap(auth.Serial.Wrap(err))
}
reply.Status = pb.AgreementsSummary_OK
s.logger.Debug("Stored Agreement...")
return reply, nil
}
func (s *Server) verifySignature(ctx context.Context, ba *pb.RenterBandwidthAllocation) error {
// TODO(security): detect replay attacks
//Deserealize RenterBandwidthAllocation.GetData() so we can get public key
rbad := &pb.RenterBandwidthAllocation_Data{}
if err := proto.Unmarshal(ba.GetData(), rbad); err != nil {
return Error.New("Failed to unmarshal RenterBandwidthAllocation: %+v", err)
}
pba := rbad.GetPayerAllocation()
pbad := &pb.PayerBandwidthAllocation_Data{}
if err := proto.Unmarshal(pba.GetData(), pbad); err != nil {
return Error.New("Failed to unmarshal PayerBandwidthAllocation: %+v", err)
}
// Extract renter's public key from PayerBandwidthAllocation_Data
pubkey, err := x509.ParsePKIXPublicKey(pbad.GetPubKey())
if err != nil {
return Error.New("Failed to extract Public Key from RenterBandwidthAllocation: %+v", err)
}
// Typecast public key
k, ok := pubkey.(*ecdsa.PublicKey)
if !ok {
return peertls.ErrUnsupportedKey.New("%T", pubkey)
}
signatureLength := k.Curve.Params().P.BitLen() / 8
if len(ba.GetSignature()) < signatureLength {
return Error.New("Invalid Renter's Signature Length")
}
// verify Renter's (uplink) signature
if ok := cryptopasta.Verify(ba.GetData(), ba.GetSignature(), k); !ok {
return Error.New("Failed to verify Renter's Signature")
}
// satellite public key
k, ok = s.pkey.(*ecdsa.PublicKey)
if !ok {
return peertls.ErrUnsupportedKey.New("%T", s.pkey)
}
signatureLength = k.Curve.Params().P.BitLen() / 8
if len(rbad.GetPayerAllocation().GetSignature()) < signatureLength {
return Error.New("Inavalid Payer's Signature Length")
}
// verify Payer's (satellite) signature
if ok := cryptopasta.Verify(rbad.GetPayerAllocation().GetData(), rbad.GetPayerAllocation().GetSignature(), k); !ok {
return Error.New("Failed to verify Payer's Signature")
}
return nil
}

View File

@ -4,107 +4,76 @@
package test
import (
"crypto"
"crypto/ecdsa"
"crypto/x509"
"time"
"github.com/gogo/protobuf/proto"
"github.com/gtank/cryptopasta"
"github.com/skyrings/skyring-common/tools/uuid"
"github.com/zeebo/errs"
"storj.io/storj/internal/teststorj"
"storj.io/storj/pkg/auth"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/storj"
)
//GeneratePayerBandwidthAllocation creates a signed PayerBandwidthAllocation from a PayerBandwidthAllocation_Action
func GeneratePayerBandwidthAllocation(action pb.PayerBandwidthAllocation_Action, satelliteKey crypto.PrivateKey, uplinkKey crypto.PrivateKey, expiration time.Duration) (*pb.PayerBandwidthAllocation, error) {
satelliteKeyEcdsa, ok := satelliteKey.(*ecdsa.PrivateKey)
if !ok {
return nil, errs.New("Satellite Private Key is not a valid *ecdsa.PrivateKey")
}
pubbytes, err := getUplinkPubKey(uplinkKey)
if err != nil {
return nil, errs.New("Uplink Private Key is not a valid *ecdsa.PrivateKey")
}
func GeneratePayerBandwidthAllocation(action pb.PayerBandwidthAllocation_Action, satID *identity.FullIdentity, upID *identity.FullIdentity, expiration time.Duration) (*pb.PayerBandwidthAllocation, error) {
serialNum, err := uuid.New()
if err != nil {
return nil, err
}
// Generate PayerBandwidthAllocation_Data
data, _ := proto.Marshal(
&pb.PayerBandwidthAllocation_Data{
SatelliteId: teststorj.NodeIDFromString("SatelliteID"),
UplinkId: teststorj.NodeIDFromString("UplinkID"),
SatelliteId: satID.ID,
UplinkId: upID.ID,
ExpirationUnixSec: time.Now().Add(expiration).Unix(),
SerialNumber: serialNum.String(),
Action: action,
CreatedUnixSec: time.Now().Unix(),
PubKey: pubbytes,
},
)
// Sign the PayerBandwidthAllocation_Data with the "Satellite" Private Key
s, err := cryptopasta.Sign(data, satelliteKeyEcdsa)
if err != nil {
return nil, errs.New("Failed to sign PayerBandwidthAllocation_Data with satellite Private Key: %+v", err)
satPrivECDSA, ok := satID.Key.(*ecdsa.PrivateKey)
if !ok {
return nil, pb.Payer.Wrap(auth.ECDSA)
}
s, err := cryptopasta.Sign(data, satPrivECDSA)
if err != nil {
return nil, pb.Payer.Wrap(auth.Sign.Wrap(err))
}
// Combine Signature and Data for PayerBandwidthAllocation
return &pb.PayerBandwidthAllocation{
Data: data,
Signature: s,
Certs: satID.ChainRaw(),
}, nil
}
//GenerateRenterBandwidthAllocation creates a signed RenterBandwidthAllocation from a PayerBandwidthAllocation
func GenerateRenterBandwidthAllocation(pba *pb.PayerBandwidthAllocation, storageNodeID storj.NodeID, uplinkKey crypto.PrivateKey) (*pb.RenterBandwidthAllocation, error) {
// get "Uplink" Public Key
uplinkKeyEcdsa, ok := uplinkKey.(*ecdsa.PrivateKey)
if !ok {
return nil, errs.New("Uplink Private Key is not a valid *ecdsa.PrivateKey")
}
func GenerateRenterBandwidthAllocation(pba *pb.PayerBandwidthAllocation, storageNodeID storj.NodeID, upID *identity.FullIdentity, total int64) (*pb.RenterBandwidthAllocation, error) {
// Generate RenterBandwidthAllocation_Data
data, _ := proto.Marshal(
&pb.RenterBandwidthAllocation_Data{
PayerAllocation: pba,
StorageNodeId: storageNodeID,
Total: int64(666),
Total: total,
},
)
// Sign the PayerBandwidthAllocation_Data with the "Uplink" Private Key
s, err := cryptopasta.Sign(data, uplinkKeyEcdsa)
if err != nil {
return nil, errs.New("Failed to sign RenterBandwidthAllocation_Data with uplink Private Key: %+v", err)
upPrivECDSA, ok := upID.Key.(*ecdsa.PrivateKey)
if !ok {
return nil, pb.Payer.Wrap(auth.ECDSA)
}
s, err := cryptopasta.Sign(data, upPrivECDSA)
if err != nil {
return nil, pb.Payer.Wrap(auth.Sign.Wrap(err))
}
// Combine Signature and Data for RenterBandwidthAllocation
return &pb.RenterBandwidthAllocation{
Signature: s,
Data: data,
Certs: upID.ChainRaw(),
}, nil
}
// get uplink's public key
func getUplinkPubKey(uplinkKey crypto.PrivateKey) ([]byte, error) {
// get "Uplink" Public Key
uplinkKeyEcdsa, ok := uplinkKey.(*ecdsa.PrivateKey)
if !ok {
return nil, errs.New("Uplink Private Key is not a valid *ecdsa.PrivateKey")
}
pubbytes, err := x509.MarshalPKIXPublicKey(&uplinkKeyEcdsa.PublicKey)
if err != nil {
return nil, errs.New("Could not generate byte array from Uplink Public key: %+v", err)
}
return pubbytes, nil
}

View File

@ -6,6 +6,9 @@ package test
import (
"context"
"crypto/ecdsa"
"crypto/tls"
"crypto/x509"
"net"
"testing"
"time"
@ -13,12 +16,16 @@ import (
"github.com/gtank/cryptopasta"
"github.com/stretchr/testify/assert"
"go.uber.org/zap"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/peer"
"storj.io/storj/internal/testcontext"
"storj.io/storj/internal/testidentity"
"storj.io/storj/internal/teststorj"
"storj.io/storj/pkg/auth"
"storj.io/storj/pkg/bwagreement"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/storj"
"storj.io/storj/satellite"
"storj.io/storj/satellite/satellitedb/satellitedbtest"
)
@ -32,18 +39,41 @@ func TestBandwidthAgreement(t *testing.T) {
})
}
func getPeerContext(ctx context.Context, t *testing.T) (context.Context, storj.NodeID) {
ident, err := testidentity.NewTestIdentity(ctx)
if !assert.NoError(t, err) || !assert.NotNil(t, ident) {
t.Fatal(err)
}
grpcPeer := &peer.Peer{
Addr: &net.TCPAddr{IP: net.ParseIP("1.2.3.4"), Port: 5},
AuthInfo: credentials.TLSInfo{
State: tls.ConnectionState{
PeerCertificates: []*x509.Certificate{ident.Leaf, ident.CA},
},
},
}
nodeID, err := identity.NodeIDFromKey(ident.CA.PublicKey)
assert.NoError(t, err)
return peer.NewContext(ctx, grpcPeer), nodeID
}
func testDatabase(ctx context.Context, t *testing.T, bwdb bwagreement.DB) {
satellitePubKey, satellitePrivKey, uplinkPrivKey := generateKeys(ctx, t)
satellite := bwagreement.NewServer(bwdb, zap.NewNop(), satellitePubKey)
upID, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err)
satID, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err)
satellite := bwagreement.NewServer(bwdb, zap.NewNop(), satID.ID)
{ // TestSameSerialNumberBandwidthAgreements
pbaFile1, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satellitePrivKey, uplinkPrivKey, time.Hour)
pbaFile1, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satID, upID, time.Hour)
assert.NoError(t, err)
rbaNode1, err := GenerateRenterBandwidthAllocation(pbaFile1, teststorj.NodeIDFromString("Storage node 1"), uplinkPrivKey)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
rbaNode1, err := GenerateRenterBandwidthAllocation(pbaFile1, storageNode1, upID, 666)
assert.NoError(t, err)
rbaNode2, err := GenerateRenterBandwidthAllocation(pbaFile1, teststorj.NodeIDFromString("Storage node 2"), uplinkPrivKey)
ctxSN2, storageNode2 := getPeerContext(ctx, t)
rbaNode2, err := GenerateRenterBandwidthAllocation(pbaFile1, storageNode2, upID, 666)
assert.NoError(t, err)
/* More than one storage node can submit bwagreements with the same serial number.
@ -51,11 +81,11 @@ func testDatabase(ctx context.Context, t *testing.T, bwdb bwagreement.DB) {
Uplink requests a PayerBandwidthAllocation from the satellite. One serial number for all storage nodes.
Uplink signes 2 RenterBandwidthAllocation for both storage node. */
{
reply, err := satellite.BandwidthAgreements(ctx, rbaNode1)
reply, err := satellite.BandwidthAgreements(ctxSN1, rbaNode1)
assert.NoError(t, err)
assert.Equal(t, pb.AgreementsSummary_OK, reply.Status)
reply, err = satellite.BandwidthAgreements(ctx, rbaNode2)
reply, err = satellite.BandwidthAgreements(ctxSN2, rbaNode2)
assert.NoError(t, err)
assert.Equal(t, pb.AgreementsSummary_OK, reply.Status)
}
@ -63,24 +93,24 @@ func testDatabase(ctx context.Context, t *testing.T, bwdb bwagreement.DB) {
/* Storage node can submit a second bwagreement with a different sequence value.
Uplink downloads another file. New PayerBandwidthAllocation with a new sequence. */
{
pbaFile2, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satellitePrivKey, uplinkPrivKey, time.Hour)
pbaFile2, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satID, upID, time.Hour)
assert.NoError(t, err)
rbaNode1, err := GenerateRenterBandwidthAllocation(pbaFile2, teststorj.NodeIDFromString("Storage node 1"), uplinkPrivKey)
rbaNode1, err := GenerateRenterBandwidthAllocation(pbaFile2, storageNode1, upID, 666)
assert.NoError(t, err)
reply, err := satellite.BandwidthAgreements(ctx, rbaNode1)
reply, err := satellite.BandwidthAgreements(ctxSN1, rbaNode1)
assert.NoError(t, err)
assert.Equal(t, pb.AgreementsSummary_OK, reply.Status)
}
/* Storage nodes can't submit a second bwagreement with the same sequence. */
{
rbaNode1, err := GenerateRenterBandwidthAllocation(pbaFile1, teststorj.NodeIDFromString("Storage node 1"), uplinkPrivKey)
rbaNode1, err := GenerateRenterBandwidthAllocation(pbaFile1, storageNode1, upID, 666)
assert.NoError(t, err)
reply, err := satellite.BandwidthAgreements(ctx, rbaNode1)
assert.EqualError(t, err, "bwagreement error: SerialNumber already exists in the PayerBandwidthAllocation")
reply, err := satellite.BandwidthAgreements(ctxSN1, rbaNode1)
assert.True(t, auth.Serial.Has(err))
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
@ -88,55 +118,61 @@ func testDatabase(ctx context.Context, t *testing.T, bwdb bwagreement.DB) {
This test is kind of duplicate cause it will most likely trigger the same sequence error.
For safety we will try it anyway to make sure nothing strange will happen */
{
reply, err := satellite.BandwidthAgreements(ctx, rbaNode2)
assert.EqualError(t, err, "bwagreement error: SerialNumber already exists in the PayerBandwidthAllocation")
reply, err := satellite.BandwidthAgreements(ctxSN2, rbaNode2)
assert.True(t, auth.Serial.Has(err))
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
}
{ // TestExpiredBandwidthAgreements
{ // storage nodes can submit a bwagreement that will expire in one second
pba, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satellitePrivKey, uplinkPrivKey, time.Second)
pba, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satID, upID, time.Second)
assert.NoError(t, err)
rba, err := GenerateRenterBandwidthAllocation(pba, teststorj.NodeIDFromString("Storage node 1"), uplinkPrivKey)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
rba, err := GenerateRenterBandwidthAllocation(pba, storageNode1, upID, 666)
assert.NoError(t, err)
reply, err := satellite.BandwidthAgreements(ctx, rba)
reply, err := satellite.BandwidthAgreements(ctxSN1, rba)
assert.NoError(t, err)
assert.Equal(t, pb.AgreementsSummary_OK, reply.Status)
}
{ // storage nodes can't submit a bwagreement that expires right now
pba, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satellitePrivKey, uplinkPrivKey, 0*time.Second)
pba, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satID, upID, 0*time.Second)
assert.NoError(t, err)
rba, err := GenerateRenterBandwidthAllocation(pba, teststorj.NodeIDFromString("Storage node 1"), uplinkPrivKey)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
rba, err := GenerateRenterBandwidthAllocation(pba, storageNode1, upID, 666)
assert.NoError(t, err)
reply, err := satellite.BandwidthAgreements(ctx, rba)
reply, err := satellite.BandwidthAgreements(ctxSN1, rba)
assert.Error(t, err)
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
{ // storage nodes can't submit a bwagreement that expires yesterday
pba, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satellitePrivKey, uplinkPrivKey, -23*time.Hour-55*time.Second)
pba, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satID, upID, -23*time.Hour-55*time.Second)
assert.NoError(t, err)
rba, err := GenerateRenterBandwidthAllocation(pba, teststorj.NodeIDFromString("Storage node 1"), uplinkPrivKey)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
rba, err := GenerateRenterBandwidthAllocation(pba, storageNode1, upID, 666)
assert.NoError(t, err)
reply, err := satellite.BandwidthAgreements(ctx, rba)
reply, err := satellite.BandwidthAgreements(ctxSN1, rba)
assert.Error(t, err)
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
}
{ // TestManipulatedBandwidthAgreements
pba, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satellitePrivKey, uplinkPrivKey, time.Hour)
assert.NoError(t, err)
pba, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satID, upID, time.Hour)
if !assert.NoError(t, err) {
t.Fatal(err)
}
rba, err := GenerateRenterBandwidthAllocation(pba, teststorj.NodeIDFromString("Storage node 1"), uplinkPrivKey)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
rba, err := GenerateRenterBandwidthAllocation(pba, storageNode1, upID, 666)
assert.NoError(t, err)
// Unmarschal Renter and Payer bwagreements
@ -156,51 +192,59 @@ func testDatabase(ctx context.Context, t *testing.T, bwdb bwagreement.DB) {
assert.NoError(t, err)
// Generate a new keypair for self signing bwagreements
_, manipPrivKey, _ := generateKeys(ctx, t)
manipPubKey, err := getUplinkPubKey(manipPrivKey)
manipID, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err)
manipCerts := manipID.ChainRaw() //todo: do we need RestChain?
manipPrivKey, ok := manipID.Key.(*ecdsa.PrivateKey)
assert.True(t, ok)
/* Storage node can't manipulate the bwagreement size (or any other field)
Satellite will verify Renter's Signature */
Satellite will verify Renter's Signature. */
{
// Using uplink signature
reply, err := satellite.BandwidthAgreements(ctx, &pb.RenterBandwidthAllocation{
Signature: rba.GetSignature(),
Data: maniprba,
})
assert.EqualError(t, err, "bwagreement error: Failed to verify Renter's Signature")
reply, err := callBWA(ctxSN1, satellite, rba.GetSignature(), maniprba, rba.GetCerts())
assert.True(t, auth.Verify.Has(err) && pb.Renter.Has(err), err.Error())
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
/* Storage node can't sign the manipulated bwagreement
Satellite will verify Renter's Signature */
Satellite will verify Renter's Signature. */
{
manipSignature, err := cryptopasta.Sign(maniprba, manipPrivKey)
assert.NoError(t, err)
// Using self created signature
reply, err := satellite.BandwidthAgreements(ctx, &pb.RenterBandwidthAllocation{
Signature: manipSignature,
Data: maniprba,
})
assert.EqualError(t, err, "bwagreement error: Failed to verify Renter's Signature")
reply, err := callBWA(ctxSN1, satellite, manipSignature, maniprba, rba.GetCerts())
assert.True(t, auth.Verify.Has(err) && pb.Renter.Has(err), err.Error())
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
/* Storage node can't replace uplink PubKey
Satellite will verify Payer's Signature */
/* Storage node can't replace uplink Certs
Satellite will check uplink Certs against uplinkeId. */
{
// Overwrite the uplink public key with our own keypair
pbaData.PubKey = manipPubKey
manipSignature, err := cryptopasta.Sign(maniprba, manipPrivKey)
assert.NoError(t, err)
// Using self created signature + public key
reply, err := callBWA(ctxSN1, satellite, manipSignature, maniprba, manipCerts)
assert.True(t, auth.Signer.Has(err) && pb.Renter.Has(err), err.Error())
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
/* Storage node can't replace uplink NodeId
Satellite will verify the Payer's Signature. */
{
// Overwrite the uplinkId with our own keypair
pbaData.UplinkId = manipID.ID
manippba, err := proto.Marshal(pbaData)
assert.NoError(t, err)
// Overwrite the uplink public key with our own keypair
rbaData.PayerAllocation = &pb.PayerBandwidthAllocation{
Signature: pba.GetSignature(),
Data: manippba,
Certs: pba.GetCerts(),
}
maniprba, err := proto.Marshal(rbaData)
@ -210,20 +254,16 @@ func testDatabase(ctx context.Context, t *testing.T, bwdb bwagreement.DB) {
assert.NoError(t, err)
// Using self created signature + public key
reply, err := satellite.BandwidthAgreements(ctx, &pb.RenterBandwidthAllocation{
Signature: manipSignature,
Data: maniprba,
})
assert.EqualError(t, err, "bwagreement error: Failed to verify Payer's Signature")
reply, err := callBWA(ctxSN1, satellite, manipSignature, maniprba, manipCerts)
assert.True(t, auth.Verify.Has(err) && pb.Payer.Has(err), err.Error())
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
/* Storage node can't self sign the PayerBandwidthAllocation.
Satellite will verify the Payer's Signature with his own public key. */
Satellite will verify the Payer's Signature. */
{
// Overwrite the uplink public key with our own keypair
pbaData.PubKey = manipPubKey
// Overwrite the uplinkId with our own keypair
pbaData.UplinkId = manipID.ID
manippba, err := proto.Marshal(pbaData)
assert.NoError(t, err)
@ -234,6 +274,7 @@ func testDatabase(ctx context.Context, t *testing.T, bwdb bwagreement.DB) {
rbaData.PayerAllocation = &pb.PayerBandwidthAllocation{
Signature: manipSignature,
Data: manippba,
Certs: pba.GetCerts(),
}
maniprba, err := proto.Marshal(rbaData)
@ -243,33 +284,92 @@ func testDatabase(ctx context.Context, t *testing.T, bwdb bwagreement.DB) {
assert.NoError(t, err)
// Using self created Payer and Renter bwagreement signatures
reply, err := satellite.BandwidthAgreements(ctx, &pb.RenterBandwidthAllocation{
Signature: manipSignature,
Data: maniprba,
})
reply, err := callBWA(ctxSN1, satellite, manipSignature, maniprba, manipCerts)
assert.True(t, auth.Verify.Has(err) && pb.Payer.Has(err), err.Error())
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
assert.EqualError(t, err, "bwagreement error: Failed to verify Payer's Signature")
/* Storage node can't replace the satellite Certs.
Satellite will check satellite certs against satelliteId. */
{
// Overwrite the uplinkId with our own keypair
pbaData.UplinkId = manipID.ID
manippba, err := proto.Marshal(pbaData)
assert.NoError(t, err)
manipSignature, err := cryptopasta.Sign(manippba, manipPrivKey)
assert.NoError(t, err)
rbaData.PayerAllocation = &pb.PayerBandwidthAllocation{
Signature: manipSignature,
Data: manippba,
Certs: manipCerts,
}
maniprba, err := proto.Marshal(rbaData)
assert.NoError(t, err)
manipSignature, err = cryptopasta.Sign(maniprba, manipPrivKey)
assert.NoError(t, err)
// Using self created Payer and Renter bwagreement signatures
reply, err := callBWA(ctxSN1, satellite, manipSignature, maniprba, manipCerts)
assert.True(t, auth.Signer.Has(err) && pb.Payer.Has(err), err.Error())
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
/* Storage node can't replace the satellite.
Satellite will verify the Satellite Id. */
{
// Overwrite the uplinkId and satelliteID with our own keypair
pbaData.UplinkId = manipID.ID
pbaData.SatelliteId = manipID.ID
manippba, err := proto.Marshal(pbaData)
assert.NoError(t, err)
manipSignature, err := cryptopasta.Sign(manippba, manipPrivKey)
assert.NoError(t, err)
rbaData.PayerAllocation = &pb.PayerBandwidthAllocation{
Signature: manipSignature,
Data: manippba,
Certs: manipCerts,
}
maniprba, err := proto.Marshal(rbaData)
assert.NoError(t, err)
manipSignature, err = cryptopasta.Sign(maniprba, manipPrivKey)
assert.NoError(t, err)
// Using self created Payer and Renter bwagreement signatures
reply, err := callBWA(ctxSN1, satellite, manipSignature, maniprba, manipCerts)
assert.True(t, pb.Payer.Has(err), err.Error())
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
}
{ //TestInvalidBandwidthAgreements
pba, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satellitePrivKey, uplinkPrivKey, time.Hour)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
ctxSN2, storageNode2 := getPeerContext(ctx, t)
pba, err := GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, satID, upID, time.Hour)
assert.NoError(t, err)
{ // Storage node sends an corrupted signuature to force a satellite crash
rba, err := GenerateRenterBandwidthAllocation(pba, teststorj.NodeIDFromString("Storage node 1"), uplinkPrivKey)
rba, err := GenerateRenterBandwidthAllocation(pba, storageNode1, upID, 666)
assert.NoError(t, err)
rba.Signature = []byte("invalid")
reply, err := satellite.BandwidthAgreements(ctx, rba)
assert.EqualError(t, err, "bwagreement error: Invalid Renter's Signature Length")
reply, err := satellite.BandwidthAgreements(ctxSN1, rba)
assert.True(t, auth.SigLen.Has(err) && pb.Renter.Has(err), err.Error())
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
{ // Storage node sends an corrupted uplink pubkey to force a crash
rba, err := GenerateRenterBandwidthAllocation(pba, teststorj.NodeIDFromString("Storage node 2"), uplinkPrivKey)
{ // Storage node sends an corrupted uplink Certs to force a crash
rba, err := GenerateRenterBandwidthAllocation(pba, storageNode2, upID, 666)
assert.NoError(t, err)
rbaData := &pb.RenterBandwidthAllocation_Data{}
@ -280,7 +380,7 @@ func testDatabase(ctx context.Context, t *testing.T, bwdb bwagreement.DB) {
err = proto.Unmarshal(pba.GetData(), pbaData)
assert.NoError(t, err)
pbaData.PubKey = nil
pba.Certs = nil
invalidpba, err := proto.Marshal(pbaData)
assert.NoError(t, err)
@ -288,35 +388,20 @@ func testDatabase(ctx context.Context, t *testing.T, bwdb bwagreement.DB) {
rbaData.PayerAllocation = &pb.PayerBandwidthAllocation{
Signature: pba.GetSignature(),
Data: invalidpba,
Certs: pba.GetCerts(),
}
invalidrba, err := proto.Marshal(rbaData)
assert.NoError(t, err)
reply, err := satellite.BandwidthAgreements(ctx, &pb.RenterBandwidthAllocation{
Signature: rba.GetSignature(),
Data: invalidrba,
})
assert.EqualError(t, err, "bwagreement error: Failed to extract Public Key from RenterBandwidthAllocation: asn1: syntax error: sequence truncated")
reply, err := callBWA(ctxSN2, satellite, rba.GetSignature(), invalidrba, rba.GetCerts())
assert.True(t, auth.Verify.Has(err) && pb.Renter.Has(err), err.Error())
assert.Equal(t, pb.AgreementsSummary_REJECTED, reply.Status)
}
}
}
func generateKeys(ctx context.Context, t *testing.T) (satellitePubKey *ecdsa.PublicKey, satellitePrivKey *ecdsa.PrivateKey, uplinkPrivKey *ecdsa.PrivateKey) {
fiS, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err)
satellitePubKey, ok := fiS.Leaf.PublicKey.(*ecdsa.PublicKey)
assert.True(t, ok)
satellitePrivKey, ok = fiS.Key.(*ecdsa.PrivateKey)
assert.True(t, ok)
fiU, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err)
uplinkPrivKey, ok = fiU.Key.(*ecdsa.PrivateKey)
assert.True(t, ok)
return
func callBWA(ctx context.Context, sat *bwagreement.Server, signature, data []byte, certs [][]byte) (*pb.AgreementsSummary, error) {
rba := &pb.RenterBandwidthAllocation{Signature: signature, Data: data, Certs: certs}
return sat.BandwidthAgreements(ctx, rba)
}

View File

@ -214,13 +214,8 @@ func (c CertificateSigner) Sign(ctx context.Context, req *pb.SigningRequest) (*p
return nil, err
}
signedChainBytes := append(
[][]byte{
signedPeerCA.Raw,
c.signer.Cert.Raw,
},
c.signer.RestChainRaw()...,
)
signedChainBytes := [][]byte{signedPeerCA.Raw, c.signer.Cert.Raw}
signedChainBytes = append(signedChainBytes, c.signer.RestChainRaw()...)
err = c.authDB.Claim(&ClaimOpts{
Req: req,
Peer: grpcPeer,

View File

@ -196,7 +196,7 @@ func NodeIDFromECDSAKey(k *ecdsa.PublicKey) (storj.NodeID, error) {
}
mid := sha256.Sum256(kb)
end := sha256.Sum256(mid[:])
return storj.NodeIDFromBytes(end[:])
return storj.NodeID(end), nil
}
// NewFullIdentity creates a new ID for nodes with difficulty and concurrency params
@ -298,6 +298,15 @@ func (ic Config) SaveBackup(fi *FullIdentity) error {
}.Save(fi)
}
// ChainRaw returns all of the certificate chain as a 2d byte slice
func (fi *FullIdentity) ChainRaw() [][]byte {
chain := [][]byte{fi.Leaf.Raw, fi.CA.Raw}
for _, cert := range fi.RestChain {
chain = append(chain, cert.Raw)
}
return chain
}
// RestChainRaw returns the rest (excluding leaf and CA) of the certificate chain as a 2d byte slice
func (fi *FullIdentity) RestChainRaw() [][]byte {
var chain [][]byte
@ -310,9 +319,7 @@ func (fi *FullIdentity) RestChainRaw() [][]byte {
// ServerOption returns a grpc `ServerOption` for incoming connections
// to the node with this full identity
func (fi *FullIdentity) ServerOption(pcvFuncs ...peertls.PeerCertVerificationFunc) (grpc.ServerOption, error) {
ch := [][]byte{fi.Leaf.Raw, fi.CA.Raw}
ch = append(ch, fi.RestChainRaw()...)
c, err := peertls.TLSCert(ch, fi.Leaf, fi.Key)
c, err := peertls.TLSCert(fi.ChainRaw(), fi.Leaf, fi.Key)
if err != nil {
return nil, err
}
@ -337,9 +344,7 @@ func (fi *FullIdentity) ServerOption(pcvFuncs ...peertls.PeerCertVerificationFun
// to the node with this peer identity
// id is an optional id of the node we are dialing
func (fi *FullIdentity) DialOption(id storj.NodeID) (grpc.DialOption, error) {
ch := [][]byte{fi.Leaf.Raw, fi.CA.Raw}
ch = append(ch, fi.RestChainRaw()...)
c, err := peertls.TLSCert(ch, fi.Leaf, fi.Key)
c, err := peertls.TLSCert(fi.ChainRaw(), fi.Leaf, fi.Key)
if err != nil {
return nil, err
}

63
pkg/pb/BandwidthUtils.go Normal file
View File

@ -0,0 +1,63 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package pb
import (
proto "github.com/gogo/protobuf/proto"
"github.com/zeebo/errs"
)
var (
//Renter wraps errors related to renter bandwidth allocations
Renter = errs.Class("Renter agreement")
//Payer wraps errors related to payer bandwidth allocations
Payer = errs.Class("Payer agreement")
//Marshal indicates a failure during serialization
Marshal = errs.Class("Could not generate byte array from key")
//Unmarshal indicates a failure during deserialization
Unmarshal = errs.Class("Could not generate key from byte array")
//Missing indicates missing or empty information
Missing = errs.Class("Required field is empty")
)
//SignedMsg interface has a key, data, and signature
type SignedMsg interface {
GetCerts() [][]byte
GetData() []byte
GetSignature() []byte
}
// MsgComplete ensures a SignedMsg has no nulls
func MsgComplete(sm SignedMsg) (bool, error) {
if sm == nil {
return false, Missing.New("message")
} else if sm.GetData() == nil {
return false, Missing.New("message data")
} else if sm.GetSignature() == nil {
return false, Missing.New("message signature")
} else if sm.GetCerts() == nil {
return false, Missing.New("message certificates")
}
return true, nil
}
//Unpack helps get things out of a RenterBandwidthAllocation
func (rba *RenterBandwidthAllocation) Unpack() (*RenterBandwidthAllocation_Data, *PayerBandwidthAllocation, *PayerBandwidthAllocation_Data, error) {
if ok, err := MsgComplete(rba); !ok {
return nil, nil, nil, Renter.Wrap(err)
}
rbad := &RenterBandwidthAllocation_Data{}
if err := proto.Unmarshal(rba.GetData(), rbad); err != nil {
return nil, nil, nil, Renter.Wrap(Unmarshal.Wrap(err))
}
if ok, err := MsgComplete(rba); !ok {
return nil, nil, nil, Payer.Wrap(err)
}
pba := rbad.GetPayerAllocation()
pbad := &PayerBandwidthAllocation_Data{}
if err := proto.Unmarshal(pba.GetData(), pbad); err != nil {
return nil, nil, nil, Payer.Wrap(Unmarshal.Wrap(err))
}
return rbad, pba, pbad, nil
}

View File

@ -54,12 +54,13 @@ func (x PayerBandwidthAllocation_Action) String() string {
return proto.EnumName(PayerBandwidthAllocation_Action_name, int32(x))
}
func (PayerBandwidthAllocation_Action) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{0, 0}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{0, 0}
}
type PayerBandwidthAllocation struct {
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
Certs [][]byte `protobuf:"bytes,1,rep,name=certs,proto3" json:"certs,omitempty"`
Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -69,7 +70,7 @@ func (m *PayerBandwidthAllocation) Reset() { *m = PayerBandwidthAllocati
func (m *PayerBandwidthAllocation) String() string { return proto.CompactTextString(m) }
func (*PayerBandwidthAllocation) ProtoMessage() {}
func (*PayerBandwidthAllocation) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{0}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{0}
}
func (m *PayerBandwidthAllocation) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PayerBandwidthAllocation.Unmarshal(m, b)
@ -89,6 +90,13 @@ func (m *PayerBandwidthAllocation) XXX_DiscardUnknown() {
var xxx_messageInfo_PayerBandwidthAllocation proto.InternalMessageInfo
func (m *PayerBandwidthAllocation) GetCerts() [][]byte {
if m != nil {
return m.Certs
}
return nil
}
func (m *PayerBandwidthAllocation) GetSignature() []byte {
if m != nil {
return m.Signature
@ -111,7 +119,6 @@ type PayerBandwidthAllocation_Data struct {
SerialNumber string `protobuf:"bytes,5,opt,name=serial_number,json=serialNumber,proto3" json:"serial_number,omitempty"`
Action PayerBandwidthAllocation_Action `protobuf:"varint,6,opt,name=action,proto3,enum=piecestoreroutes.PayerBandwidthAllocation_Action" json:"action,omitempty"`
CreatedUnixSec int64 `protobuf:"varint,7,opt,name=created_unix_sec,json=createdUnixSec,proto3" json:"created_unix_sec,omitempty"`
PubKey []byte `protobuf:"bytes,8,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -121,7 +128,7 @@ func (m *PayerBandwidthAllocation_Data) Reset() { *m = PayerBandwidthAll
func (m *PayerBandwidthAllocation_Data) String() string { return proto.CompactTextString(m) }
func (*PayerBandwidthAllocation_Data) ProtoMessage() {}
func (*PayerBandwidthAllocation_Data) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{0, 0}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{0, 0}
}
func (m *PayerBandwidthAllocation_Data) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PayerBandwidthAllocation_Data.Unmarshal(m, b)
@ -176,16 +183,10 @@ func (m *PayerBandwidthAllocation_Data) GetCreatedUnixSec() int64 {
return 0
}
func (m *PayerBandwidthAllocation_Data) GetPubKey() []byte {
if m != nil {
return m.PubKey
}
return nil
}
type RenterBandwidthAllocation struct {
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
Certs [][]byte `protobuf:"bytes,1,rep,name=certs,proto3" json:"certs,omitempty"`
Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -195,7 +196,7 @@ func (m *RenterBandwidthAllocation) Reset() { *m = RenterBandwidthAlloca
func (m *RenterBandwidthAllocation) String() string { return proto.CompactTextString(m) }
func (*RenterBandwidthAllocation) ProtoMessage() {}
func (*RenterBandwidthAllocation) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{1}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{1}
}
func (m *RenterBandwidthAllocation) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RenterBandwidthAllocation.Unmarshal(m, b)
@ -215,6 +216,13 @@ func (m *RenterBandwidthAllocation) XXX_DiscardUnknown() {
var xxx_messageInfo_RenterBandwidthAllocation proto.InternalMessageInfo
func (m *RenterBandwidthAllocation) GetCerts() [][]byte {
if m != nil {
return m.Certs
}
return nil
}
func (m *RenterBandwidthAllocation) GetSignature() []byte {
if m != nil {
return m.Signature
@ -230,7 +238,7 @@ func (m *RenterBandwidthAllocation) GetData() []byte {
}
type RenterBandwidthAllocation_Data struct {
PayerAllocation *PayerBandwidthAllocation `protobuf:"bytes,1,opt,name=payer_allocation,json=payerAllocation" json:"payer_allocation,omitempty"`
PayerAllocation *PayerBandwidthAllocation `protobuf:"bytes,1,opt,name=payer_allocation,json=payerAllocation,proto3" json:"payer_allocation,omitempty"`
Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"`
StorageNodeId NodeID `protobuf:"bytes,3,opt,name=storage_node_id,json=storageNodeId,proto3,customtype=NodeID" json:"storage_node_id"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@ -242,7 +250,7 @@ func (m *RenterBandwidthAllocation_Data) Reset() { *m = RenterBandwidthA
func (m *RenterBandwidthAllocation_Data) String() string { return proto.CompactTextString(m) }
func (*RenterBandwidthAllocation_Data) ProtoMessage() {}
func (*RenterBandwidthAllocation_Data) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{1, 0}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{1, 0}
}
func (m *RenterBandwidthAllocation_Data) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RenterBandwidthAllocation_Data.Unmarshal(m, b)
@ -277,9 +285,9 @@ func (m *RenterBandwidthAllocation_Data) GetTotal() int64 {
}
type PieceStore struct {
BandwidthAllocation *RenterBandwidthAllocation `protobuf:"bytes,1,opt,name=bandwidth_allocation,json=bandwidthAllocation" json:"bandwidth_allocation,omitempty"`
PieceData *PieceStore_PieceData `protobuf:"bytes,2,opt,name=piece_data,json=pieceData" json:"piece_data,omitempty"`
Authorization *SignedMessage `protobuf:"bytes,3,opt,name=authorization" json:"authorization,omitempty"`
BandwidthAllocation *RenterBandwidthAllocation `protobuf:"bytes,1,opt,name=bandwidth_allocation,json=bandwidthAllocation,proto3" json:"bandwidth_allocation,omitempty"`
PieceData *PieceStore_PieceData `protobuf:"bytes,2,opt,name=piece_data,json=pieceData,proto3" json:"piece_data,omitempty"`
Authorization *SignedMessage `protobuf:"bytes,3,opt,name=authorization,proto3" json:"authorization,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -289,7 +297,7 @@ func (m *PieceStore) Reset() { *m = PieceStore{} }
func (m *PieceStore) String() string { return proto.CompactTextString(m) }
func (*PieceStore) ProtoMessage() {}
func (*PieceStore) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{2}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{2}
}
func (m *PieceStore) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PieceStore.Unmarshal(m, b)
@ -344,7 +352,7 @@ func (m *PieceStore_PieceData) Reset() { *m = PieceStore_PieceData{} }
func (m *PieceStore_PieceData) String() string { return proto.CompactTextString(m) }
func (*PieceStore_PieceData) ProtoMessage() {}
func (*PieceStore_PieceData) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{2, 0}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{2, 0}
}
func (m *PieceStore_PieceData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PieceStore_PieceData.Unmarshal(m, b)
@ -388,7 +396,7 @@ func (m *PieceStore_PieceData) GetContent() []byte {
type PieceId struct {
// TODO: may want to use customtype and fixed-length byte slice
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Authorization *SignedMessage `protobuf:"bytes,2,opt,name=authorization" json:"authorization,omitempty"`
Authorization *SignedMessage `protobuf:"bytes,2,opt,name=authorization,proto3" json:"authorization,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -398,7 +406,7 @@ func (m *PieceId) Reset() { *m = PieceId{} }
func (m *PieceId) String() string { return proto.CompactTextString(m) }
func (*PieceId) ProtoMessage() {}
func (*PieceId) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{3}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{3}
}
func (m *PieceId) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PieceId.Unmarshal(m, b)
@ -445,7 +453,7 @@ func (m *PieceSummary) Reset() { *m = PieceSummary{} }
func (m *PieceSummary) String() string { return proto.CompactTextString(m) }
func (*PieceSummary) ProtoMessage() {}
func (*PieceSummary) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{4}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{4}
}
func (m *PieceSummary) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PieceSummary.Unmarshal(m, b)
@ -487,9 +495,9 @@ func (m *PieceSummary) GetExpirationUnixSec() int64 {
}
type PieceRetrieval struct {
BandwidthAllocation *RenterBandwidthAllocation `protobuf:"bytes,1,opt,name=bandwidth_allocation,json=bandwidthAllocation" json:"bandwidth_allocation,omitempty"`
PieceData *PieceRetrieval_PieceData `protobuf:"bytes,2,opt,name=piece_data,json=pieceData" json:"piece_data,omitempty"`
Authorization *SignedMessage `protobuf:"bytes,3,opt,name=authorization" json:"authorization,omitempty"`
BandwidthAllocation *RenterBandwidthAllocation `protobuf:"bytes,1,opt,name=bandwidth_allocation,json=bandwidthAllocation,proto3" json:"bandwidth_allocation,omitempty"`
PieceData *PieceRetrieval_PieceData `protobuf:"bytes,2,opt,name=piece_data,json=pieceData,proto3" json:"piece_data,omitempty"`
Authorization *SignedMessage `protobuf:"bytes,3,opt,name=authorization,proto3" json:"authorization,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -499,7 +507,7 @@ func (m *PieceRetrieval) Reset() { *m = PieceRetrieval{} }
func (m *PieceRetrieval) String() string { return proto.CompactTextString(m) }
func (*PieceRetrieval) ProtoMessage() {}
func (*PieceRetrieval) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{5}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{5}
}
func (m *PieceRetrieval) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PieceRetrieval.Unmarshal(m, b)
@ -554,7 +562,7 @@ func (m *PieceRetrieval_PieceData) Reset() { *m = PieceRetrieval_PieceDa
func (m *PieceRetrieval_PieceData) String() string { return proto.CompactTextString(m) }
func (*PieceRetrieval_PieceData) ProtoMessage() {}
func (*PieceRetrieval_PieceData) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{5, 0}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{5, 0}
}
func (m *PieceRetrieval_PieceData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PieceRetrieval_PieceData.Unmarshal(m, b)
@ -607,7 +615,7 @@ func (m *PieceRetrievalStream) Reset() { *m = PieceRetrievalStream{} }
func (m *PieceRetrievalStream) String() string { return proto.CompactTextString(m) }
func (*PieceRetrievalStream) ProtoMessage() {}
func (*PieceRetrievalStream) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{6}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{6}
}
func (m *PieceRetrievalStream) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PieceRetrievalStream.Unmarshal(m, b)
@ -644,7 +652,7 @@ func (m *PieceRetrievalStream) GetContent() []byte {
type PieceDelete struct {
// TODO: may want to use customtype and fixed-length byte slice
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Authorization *SignedMessage `protobuf:"bytes,3,opt,name=authorization" json:"authorization,omitempty"`
Authorization *SignedMessage `protobuf:"bytes,3,opt,name=authorization,proto3" json:"authorization,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -654,7 +662,7 @@ func (m *PieceDelete) Reset() { *m = PieceDelete{} }
func (m *PieceDelete) String() string { return proto.CompactTextString(m) }
func (*PieceDelete) ProtoMessage() {}
func (*PieceDelete) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{7}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{7}
}
func (m *PieceDelete) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PieceDelete.Unmarshal(m, b)
@ -699,7 +707,7 @@ func (m *PieceDeleteSummary) Reset() { *m = PieceDeleteSummary{} }
func (m *PieceDeleteSummary) String() string { return proto.CompactTextString(m) }
func (*PieceDeleteSummary) ProtoMessage() {}
func (*PieceDeleteSummary) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{8}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{8}
}
func (m *PieceDeleteSummary) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PieceDeleteSummary.Unmarshal(m, b)
@ -738,7 +746,7 @@ func (m *PieceStoreSummary) Reset() { *m = PieceStoreSummary{} }
func (m *PieceStoreSummary) String() string { return proto.CompactTextString(m) }
func (*PieceStoreSummary) ProtoMessage() {}
func (*PieceStoreSummary) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{9}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{9}
}
func (m *PieceStoreSummary) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PieceStoreSummary.Unmarshal(m, b)
@ -782,7 +790,7 @@ func (m *StatsReq) Reset() { *m = StatsReq{} }
func (m *StatsReq) String() string { return proto.CompactTextString(m) }
func (*StatsReq) ProtoMessage() {}
func (*StatsReq) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{10}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{10}
}
func (m *StatsReq) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StatsReq.Unmarshal(m, b)
@ -816,7 +824,7 @@ func (m *StatSummary) Reset() { *m = StatSummary{} }
func (m *StatSummary) String() string { return proto.CompactTextString(m) }
func (*StatSummary) ProtoMessage() {}
func (*StatSummary) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{11}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{11}
}
func (m *StatSummary) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StatSummary.Unmarshal(m, b)
@ -877,7 +885,7 @@ func (m *SignedMessage) Reset() { *m = SignedMessage{} }
func (m *SignedMessage) String() string { return proto.CompactTextString(m) }
func (*SignedMessage) ProtoMessage() {}
func (*SignedMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{12}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{12}
}
func (m *SignedMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SignedMessage.Unmarshal(m, b)
@ -928,7 +936,7 @@ func (m *DashboardReq) Reset() { *m = DashboardReq{} }
func (m *DashboardReq) String() string { return proto.CompactTextString(m) }
func (*DashboardReq) ProtoMessage() {}
func (*DashboardReq) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{13}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{13}
}
func (m *DashboardReq) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DashboardReq.Unmarshal(m, b)
@ -952,9 +960,9 @@ type DashboardStats struct {
NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"`
NodeConnections int64 `protobuf:"varint,2,opt,name=node_connections,json=nodeConnections,proto3" json:"node_connections,omitempty"`
Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
Stats *StatSummary `protobuf:"bytes,4,opt,name=stats" json:"stats,omitempty"`
Stats *StatSummary `protobuf:"bytes,4,opt,name=stats,proto3" json:"stats,omitempty"`
Connection bool `protobuf:"varint,5,opt,name=connection,proto3" json:"connection,omitempty"`
Uptime *duration.Duration `protobuf:"bytes,6,opt,name=uptime" json:"uptime,omitempty"`
Uptime *duration.Duration `protobuf:"bytes,6,opt,name=uptime,proto3" json:"uptime,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -964,7 +972,7 @@ func (m *DashboardStats) Reset() { *m = DashboardStats{} }
func (m *DashboardStats) String() string { return proto.CompactTextString(m) }
func (*DashboardStats) ProtoMessage() {}
func (*DashboardStats) Descriptor() ([]byte, []int) {
return fileDescriptor_piecestore_4b57efffb1b6b03f, []int{14}
return fileDescriptor_piecestore_ad8894e1f36b2897, []int{14}
}
func (m *DashboardStats) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DashboardStats.Unmarshal(m, b)
@ -1380,79 +1388,79 @@ var _PieceStoreRoutes_serviceDesc = grpc.ServiceDesc{
Metadata: "piecestore.proto",
}
func init() { proto.RegisterFile("piecestore.proto", fileDescriptor_piecestore_4b57efffb1b6b03f) }
func init() { proto.RegisterFile("piecestore.proto", fileDescriptor_piecestore_ad8894e1f36b2897) }
var fileDescriptor_piecestore_4b57efffb1b6b03f = []byte{
// 1130 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x4b, 0x6f, 0xdb, 0xc6,
0x13, 0x17, 0x29, 0x5b, 0x8f, 0x91, 0x25, 0x2b, 0x9b, 0xe0, 0xff, 0x97, 0x85, 0xd8, 0x16, 0x98,
0x26, 0x55, 0x13, 0x40, 0x8e, 0x15, 0xa0, 0x77, 0xbb, 0x32, 0x02, 0xa1, 0xa8, 0xe3, 0xae, 0xec,
0x4b, 0x0e, 0x65, 0x56, 0xe4, 0x58, 0x26, 0x42, 0x91, 0x2c, 0xb9, 0x74, 0x6d, 0x7f, 0xa5, 0xa2,
0xdf, 0xa3, 0x9f, 0xa0, 0x87, 0x1e, 0x02, 0x14, 0xe8, 0xb9, 0xc7, 0x5e, 0x0a, 0x14, 0xc5, 0xee,
0xf2, 0x21, 0x5b, 0x0f, 0x17, 0x41, 0x73, 0xdb, 0x79, 0xec, 0xcc, 0xec, 0x6f, 0x7f, 0xb3, 0xb3,
0xd0, 0x0c, 0x1c, 0xb4, 0x30, 0xe2, 0x7e, 0x88, 0xbd, 0x20, 0xf4, 0xb9, 0x4f, 0x66, 0x34, 0xa1,
0x1f, 0x73, 0x8c, 0xda, 0xe0, 0xf9, 0x76, 0x62, 0x6d, 0xc3, 0xc4, 0x9f, 0xf8, 0xc9, 0x7a, 0x67,
0xe2, 0xfb, 0x13, 0x17, 0xf7, 0xa4, 0x34, 0x8e, 0xcf, 0xf7, 0xec, 0x38, 0x64, 0xdc, 0xf1, 0x3d,
0x65, 0x37, 0xfe, 0x2e, 0x42, 0xeb, 0x84, 0x5d, 0x63, 0x78, 0xc8, 0x3c, 0xfb, 0x07, 0xc7, 0xe6,
0x17, 0x07, 0xae, 0xeb, 0x5b, 0xd2, 0x85, 0x3c, 0x86, 0x6a, 0xe4, 0x4c, 0x3c, 0xc6, 0xe3, 0x10,
0x5b, 0x5a, 0x47, 0xeb, 0x6e, 0xd0, 0x5c, 0x41, 0x08, 0xac, 0xd9, 0x8c, 0xb3, 0x96, 0x2e, 0x0d,
0x72, 0xdd, 0xfe, 0x5d, 0x87, 0xb5, 0x01, 0xe3, 0x8c, 0xec, 0xc3, 0x46, 0xc4, 0x38, 0xba, 0xae,
0xc3, 0xd1, 0x74, 0x6c, 0xb5, 0xfb, 0xb0, 0xf1, 0xf3, 0x87, 0xdd, 0xc2, 0xaf, 0x1f, 0x76, 0x4b,
0xc7, 0xbe, 0x8d, 0xc3, 0x01, 0xad, 0x65, 0x3e, 0x43, 0x9b, 0xbc, 0x80, 0x6a, 0x1c, 0xb8, 0x8e,
0xf7, 0x5e, 0xf8, 0xeb, 0x0b, 0xfd, 0x2b, 0xca, 0x61, 0x68, 0x93, 0x2d, 0xa8, 0x4c, 0xd9, 0x95,
0x19, 0x39, 0x37, 0xd8, 0x2a, 0x76, 0xb4, 0x6e, 0x91, 0x96, 0xa7, 0xec, 0x6a, 0xe4, 0xdc, 0x20,
0xe9, 0xc1, 0x43, 0xbc, 0x0a, 0x1c, 0x75, 0x4c, 0x33, 0xf6, 0x9c, 0x2b, 0x33, 0x42, 0xab, 0xb5,
0x26, 0xbd, 0x1e, 0xe4, 0xa6, 0x33, 0xcf, 0xb9, 0x1a, 0xa1, 0x45, 0x9e, 0x40, 0x3d, 0xc2, 0xd0,
0x61, 0xae, 0xe9, 0xc5, 0xd3, 0x31, 0x86, 0xad, 0xf5, 0x8e, 0xd6, 0xad, 0xd2, 0x0d, 0xa5, 0x3c,
0x96, 0x3a, 0x32, 0x84, 0x12, 0xb3, 0xc4, 0xae, 0x56, 0xa9, 0xa3, 0x75, 0x1b, 0xfd, 0xfd, 0xde,
0xdd, 0x2b, 0xe8, 0x2d, 0x83, 0xb1, 0x77, 0x20, 0x37, 0xd2, 0x24, 0x00, 0xe9, 0x42, 0xd3, 0x0a,
0x91, 0x71, 0xb4, 0xf3, 0xe2, 0xca, 0xb2, 0xb8, 0x46, 0xa2, 0x4f, 0x2b, 0xfb, 0x3f, 0x94, 0x83,
0x78, 0x6c, 0xbe, 0xc7, 0xeb, 0x56, 0x45, 0x82, 0x5c, 0x0a, 0xe2, 0xf1, 0xd7, 0x78, 0x6d, 0x0c,
0xa1, 0xa4, 0x82, 0x92, 0x32, 0x14, 0x4f, 0xce, 0x4e, 0x9b, 0x05, 0xb1, 0x78, 0x7d, 0x74, 0xda,
0xd4, 0x48, 0x1d, 0xaa, 0xaf, 0x8f, 0x4e, 0xcd, 0x83, 0xb3, 0xc1, 0xf0, 0xb4, 0xa9, 0x93, 0x06,
0x80, 0x10, 0xe9, 0xd1, 0xc9, 0xc1, 0x90, 0x36, 0x8b, 0x42, 0x3e, 0x39, 0xcb, 0xe4, 0x35, 0xe3,
0x2f, 0x0d, 0xb6, 0x28, 0x7a, 0xfc, 0xbf, 0x62, 0xc0, 0x8f, 0x5a, 0xc2, 0x80, 0x33, 0x68, 0x06,
0x02, 0x11, 0x93, 0x65, 0xe1, 0x64, 0x84, 0x5a, 0xff, 0xf9, 0xbf, 0xc7, 0x8e, 0x6e, 0xca, 0x18,
0x33, 0x15, 0x3d, 0x82, 0x75, 0xee, 0x73, 0xe6, 0xca, 0xa4, 0x45, 0xaa, 0x04, 0xf2, 0x25, 0x6c,
0x8a, 0x70, 0x6c, 0x82, 0xa6, 0x68, 0x04, 0xc1, 0xa0, 0xe2, 0x42, 0x06, 0xd5, 0x13, 0x37, 0x29,
0xda, 0xc6, 0x6f, 0x3a, 0xc0, 0x89, 0x28, 0x66, 0x24, 0x8a, 0x21, 0xdf, 0xc1, 0xa3, 0x71, 0x5a,
0xc4, 0x7c, 0xdd, 0x2f, 0xe6, 0xeb, 0x5e, 0x8a, 0x1c, 0x7d, 0x38, 0x5e, 0x00, 0xe7, 0x11, 0x80,
0x0c, 0x61, 0x66, 0xb0, 0xd5, 0xfa, 0xcf, 0x16, 0xa0, 0x91, 0x55, 0xa4, 0x96, 0x02, 0x4f, 0x5a,
0x0d, 0xd2, 0x25, 0x39, 0x82, 0x3a, 0x8b, 0xf9, 0x85, 0x1f, 0x3a, 0x37, 0xaa, 0xbe, 0xa2, 0x8c,
0xb4, 0x3b, 0x1f, 0x69, 0xe4, 0x4c, 0x3c, 0xb4, 0xbf, 0xc1, 0x28, 0x62, 0x13, 0xa4, 0xb7, 0x77,
0xb5, 0x11, 0xaa, 0x59, 0x78, 0xd2, 0x00, 0x3d, 0x69, 0xd3, 0x2a, 0xd5, 0x1d, 0x7b, 0x59, 0x17,
0xe9, 0xcb, 0xba, 0xa8, 0x05, 0x65, 0xcb, 0xf7, 0x38, 0x7a, 0x5c, 0x21, 0x4f, 0x53, 0xd1, 0x78,
0x07, 0x65, 0x99, 0x66, 0x68, 0xcf, 0x25, 0x99, 0x3b, 0x88, 0xfe, 0x31, 0x07, 0x31, 0xa6, 0xb0,
0xa1, 0x20, 0x8b, 0xa7, 0x53, 0x16, 0x5e, 0xcf, 0xa5, 0xd9, 0x4e, 0x61, 0x97, 0xcf, 0x85, 0x3a,
0x82, 0x82, 0x73, 0xd5, 0x83, 0x51, 0x5c, 0x72, 0x54, 0xe3, 0x17, 0x1d, 0x1a, 0x32, 0x1f, 0x45,
0x1e, 0x3a, 0x78, 0xc9, 0xdc, 0x4f, 0x4e, 0x9c, 0xe1, 0x02, 0xe2, 0x3c, 0x5f, 0x42, 0x9c, 0xac,
0xaa, 0x4f, 0x4a, 0x1e, 0xba, 0x8a, 0x3c, 0xf7, 0x00, 0xfe, 0x3f, 0x28, 0xf9, 0xe7, 0xe7, 0x11,
0xf2, 0x04, 0xe3, 0x44, 0x32, 0xde, 0xc0, 0xa3, 0xdb, 0x27, 0x18, 0xf1, 0x10, 0xd9, 0xf4, 0x4e,
0x38, 0xed, 0x6e, 0xb8, 0x19, 0xea, 0xe9, 0xb7, 0xa9, 0x67, 0x43, 0x4d, 0x15, 0x89, 0x2e, 0x72,
0xbc, 0x9f, 0x7e, 0x1f, 0x05, 0x85, 0xd1, 0x03, 0x32, 0x93, 0x25, 0x25, 0x61, 0x0b, 0xca, 0x53,
0xe5, 0x9f, 0x64, 0x4c, 0x45, 0xe3, 0x14, 0x1e, 0xe4, 0x1d, 0x7e, 0xaf, 0x3b, 0x79, 0x0a, 0x0d,
0xf9, 0xc8, 0x99, 0x21, 0x5a, 0xe8, 0x5c, 0xa2, 0x9d, 0x00, 0x5a, 0x97, 0x5a, 0x9a, 0x28, 0x0d,
0x80, 0xca, 0x88, 0x33, 0x1e, 0x51, 0xfc, 0xde, 0xf8, 0x49, 0x83, 0x9a, 0x10, 0xd2, 0xe0, 0xdb,
0x00, 0x71, 0x84, 0xb6, 0x19, 0x05, 0xcc, 0xca, 0x00, 0x14, 0x9a, 0x91, 0x50, 0x90, 0xcf, 0x61,
0x93, 0x5d, 0x32, 0xc7, 0x65, 0x63, 0x17, 0x13, 0x1f, 0x95, 0xa2, 0x91, 0xa9, 0x95, 0xe3, 0x53,
0x68, 0xc8, 0x38, 0x19, 0x45, 0x93, 0x0b, 0xac, 0x0b, 0x6d, 0x46, 0x66, 0xb2, 0x07, 0x0f, 0xf3,
0x78, 0xb9, 0xaf, 0x9a, 0xc0, 0x24, 0x33, 0x65, 0x1b, 0x8c, 0x77, 0x50, 0xbf, 0x85, 0x70, 0x36,
0x59, 0xb4, 0x7c, 0xb2, 0xdc, 0x9e, 0x45, 0xfa, 0xdd, 0x59, 0x24, 0x38, 0x12, 0x8f, 0x5d, 0xc7,
0x92, 0xe3, 0x52, 0x3d, 0x41, 0x55, 0xa5, 0x11, 0x13, 0xb3, 0x01, 0x1b, 0x03, 0x16, 0x5d, 0x8c,
0x7d, 0x16, 0xda, 0x02, 0xa1, 0x3f, 0x35, 0x68, 0x64, 0x0a, 0x89, 0x9b, 0x98, 0xb6, 0xe9, 0xec,
0x50, 0x37, 0x50, 0xf2, 0xe4, 0x90, 0x20, 0x5f, 0x40, 0x53, 0x1a, 0x2c, 0xdf, 0xf3, 0x50, 0x8e,
0xdd, 0x28, 0xc1, 0x67, 0x53, 0xe8, 0xbf, 0xca, 0xd5, 0xe2, 0x16, 0x99, 0x6d, 0x87, 0x18, 0x45,
0xb2, 0x84, 0x2a, 0x4d, 0x45, 0xf2, 0x0a, 0xd6, 0x23, 0x91, 0x46, 0xa2, 0x50, 0xeb, 0x6f, 0x2f,
0xe0, 0x58, 0x7e, 0x61, 0x54, 0xf9, 0x92, 0x1d, 0x80, 0x3c, 0xa9, 0xfc, 0x97, 0x54, 0xe8, 0x8c,
0x86, 0xec, 0x43, 0x29, 0x0e, 0xb8, 0x33, 0x45, 0xf9, 0x2b, 0xa9, 0xf5, 0xb7, 0x7a, 0xea, 0xbb,
0xd7, 0x4b, 0xbf, 0x7b, 0xbd, 0x41, 0xf2, 0xdd, 0xa3, 0x89, 0x63, 0xff, 0x8f, 0x22, 0x34, 0x73,
0xf6, 0x51, 0x99, 0x9a, 0x0c, 0x60, 0x5d, 0xea, 0xc8, 0xd6, 0x92, 0x37, 0x65, 0x68, 0xb7, 0x77,
0x96, 0xcd, 0x29, 0x55, 0xb2, 0x51, 0x20, 0x6f, 0xa1, 0x92, 0x74, 0x2e, 0x92, 0xce, 0x7d, 0x8f,
0x53, 0xfb, 0xd9, 0x7d, 0x1e, 0xaa, 0xf9, 0x8d, 0x42, 0x57, 0x7b, 0xa9, 0x91, 0x63, 0x58, 0x57,
0x23, 0xfa, 0xf1, 0xaa, 0x71, 0xd9, 0x7e, 0xb2, 0xca, 0x9a, 0x55, 0xda, 0xd5, 0xc8, 0x1b, 0x28,
0x25, 0x8f, 0xc2, 0xf6, 0x92, 0x2d, 0xca, 0xdc, 0xfe, 0x6c, 0xa5, 0x39, 0x3f, 0xfc, 0x40, 0x14,
0x28, 0xee, 0xac, 0xbd, 0xf8, 0x66, 0x45, 0x5f, 0xb6, 0x57, 0xdf, 0xba, 0x51, 0x20, 0xdf, 0x42,
0x35, 0x63, 0x25, 0x59, 0x80, 0xf8, 0x2c, 0x87, 0xdb, 0x9d, 0x15, 0x76, 0x99, 0xd2, 0x28, 0xbc,
0xd4, 0x0e, 0xd7, 0xde, 0xea, 0xc1, 0x78, 0x5c, 0x92, 0x8c, 0x78, 0xf5, 0x4f, 0x00, 0x00, 0x00,
0xff, 0xff, 0x14, 0xe3, 0x9c, 0x65, 0x4c, 0x0c, 0x00, 0x00,
var fileDescriptor_piecestore_ad8894e1f36b2897 = []byte{
// 1121 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcd, 0x6e, 0xdb, 0x46,
0x10, 0x16, 0x29, 0x5b, 0xb2, 0x46, 0x3f, 0x56, 0x36, 0x46, 0x2b, 0x0b, 0xb1, 0x2d, 0x30, 0x4d,
0xaa, 0x26, 0x80, 0x1c, 0x3b, 0x40, 0xef, 0x76, 0x65, 0x04, 0x42, 0x51, 0xc7, 0x5d, 0xd9, 0x97,
0x1c, 0xca, 0xac, 0xc8, 0xb1, 0x4c, 0x84, 0x22, 0x55, 0x72, 0xe9, 0xda, 0x7e, 0x8b, 0x3e, 0x47,
0xd1, 0xf7, 0x28, 0xd0, 0x7b, 0x0f, 0x3d, 0x04, 0xe8, 0x0b, 0xf4, 0xd8, 0x4b, 0x2f, 0xc5, 0xfe,
0x88, 0xb4, 0xad, 0xbf, 0x22, 0x80, 0x6f, 0x3b, 0x3f, 0x3b, 0x33, 0xfb, 0xcd, 0xb7, 0x3b, 0x0b,
0xf5, 0xb1, 0x87, 0x0e, 0xc6, 0x3c, 0x8c, 0xb0, 0x33, 0x8e, 0x42, 0x1e, 0x92, 0x5b, 0x9a, 0x28,
0x4c, 0x38, 0xc6, 0x4d, 0x08, 0x42, 0x57, 0x5b, 0x9b, 0x30, 0x0c, 0x87, 0xa1, 0x5e, 0x6f, 0x0f,
0xc3, 0x70, 0xe8, 0xe3, 0xae, 0x94, 0x06, 0xc9, 0xf9, 0xae, 0x9b, 0x44, 0x8c, 0x7b, 0x61, 0xa0,
0xec, 0xd6, 0xbf, 0x79, 0x68, 0x9c, 0xb0, 0x6b, 0x8c, 0x0e, 0x59, 0xe0, 0xfe, 0xe4, 0xb9, 0xfc,
0xe2, 0xc0, 0xf7, 0x43, 0x47, 0xba, 0x90, 0x0d, 0x58, 0x75, 0x30, 0xe2, 0x71, 0xc3, 0x68, 0xe5,
0xdb, 0x15, 0xaa, 0x04, 0xf2, 0x04, 0x4a, 0xb1, 0x37, 0x0c, 0x18, 0x4f, 0x22, 0x6c, 0x98, 0x2d,
0xa3, 0x5d, 0xa1, 0x99, 0x82, 0x10, 0x58, 0x71, 0x19, 0x67, 0x8d, 0xbc, 0x34, 0xc8, 0x75, 0xf3,
0x77, 0x13, 0x56, 0xba, 0x8c, 0x33, 0xb2, 0x07, 0x95, 0x98, 0x71, 0xf4, 0x7d, 0x8f, 0xa3, 0xed,
0xb9, 0x0d, 0x43, 0x38, 0x1d, 0xd6, 0x7e, 0xfb, 0xb8, 0x93, 0xfb, 0xf3, 0xe3, 0x4e, 0xe1, 0x38,
0x74, 0xb1, 0xd7, 0xa5, 0xe5, 0xd4, 0xa7, 0xe7, 0x92, 0x97, 0x50, 0x4a, 0xc6, 0xbe, 0x17, 0x7c,
0x10, 0xfe, 0xe6, 0x4c, 0xff, 0x35, 0xe5, 0xd0, 0x73, 0xc9, 0x26, 0xac, 0x8d, 0xd8, 0x95, 0x1d,
0x7b, 0x37, 0x28, 0x0b, 0xc8, 0xd3, 0xe2, 0x88, 0x5d, 0xf5, 0xbd, 0x1b, 0x24, 0x1d, 0x78, 0x8c,
0x57, 0x63, 0x4f, 0x1d, 0xde, 0x4e, 0x02, 0xef, 0xca, 0x8e, 0xd1, 0x69, 0xac, 0x48, 0xaf, 0x47,
0x99, 0xe9, 0x2c, 0xf0, 0xae, 0xfa, 0xe8, 0x90, 0xa7, 0x50, 0x8d, 0x31, 0xf2, 0x98, 0x6f, 0x07,
0xc9, 0x68, 0x80, 0x51, 0x63, 0xb5, 0x65, 0xb4, 0x4b, 0xb4, 0xa2, 0x94, 0xc7, 0x52, 0x47, 0x7a,
0x50, 0x60, 0x8e, 0xd8, 0xd5, 0x28, 0xb4, 0x8c, 0x76, 0x6d, 0x7f, 0xaf, 0x73, 0xbf, 0x31, 0x9d,
0x79, 0xe0, 0x76, 0x0e, 0xe4, 0x46, 0xaa, 0x03, 0x90, 0x36, 0xd4, 0x9d, 0x08, 0x19, 0x47, 0x37,
0x2b, 0xae, 0x28, 0x8b, 0xab, 0x69, 0xbd, 0xae, 0xcc, 0xea, 0x41, 0x41, 0xed, 0x25, 0x45, 0xc8,
0x9f, 0x9c, 0x9d, 0xd6, 0x73, 0x62, 0xf1, 0xe6, 0xe8, 0xb4, 0x6e, 0x90, 0x2a, 0x94, 0xde, 0x1c,
0x9d, 0xda, 0x07, 0x67, 0xdd, 0xde, 0x69, 0xdd, 0x24, 0x35, 0x00, 0x21, 0xd2, 0xa3, 0x93, 0x83,
0x1e, 0xad, 0xe7, 0x85, 0x7c, 0x72, 0x96, 0xca, 0x2b, 0xd6, 0xcf, 0x26, 0x6c, 0x52, 0x0c, 0xf8,
0xc3, 0xb6, 0xff, 0x17, 0x43, 0xb7, 0xff, 0x0c, 0xea, 0x63, 0x01, 0x87, 0xcd, 0xd2, 0x24, 0x92,
0x02, 0xe5, 0xfd, 0x17, 0xff, 0x1f, 0x38, 0xba, 0x2e, 0x63, 0xdc, 0xad, 0x93, 0x87, 0x9c, 0xf9,
0xb2, 0x9a, 0x3c, 0x55, 0x02, 0xf9, 0x1a, 0xd6, 0x45, 0x38, 0x36, 0x44, 0x5b, 0xdc, 0x0d, 0x41,
0x9f, 0xfc, 0x4c, 0xfa, 0x54, 0xb5, 0x9b, 0x14, 0x5d, 0xeb, 0x2f, 0x13, 0xe0, 0x44, 0x14, 0xd3,
0x17, 0xc5, 0x90, 0x1f, 0x60, 0x63, 0x30, 0x29, 0x62, 0xba, 0xee, 0x97, 0xd3, 0x75, 0xcf, 0xc5,
0x93, 0x3e, 0x1e, 0xcc, 0x00, 0xf9, 0x08, 0x40, 0x86, 0xb0, 0x25, 0x6c, 0xa6, 0x8c, 0xfa, 0x7c,
0x06, 0x1a, 0x69, 0x45, 0x6a, 0x29, 0xf0, 0xa4, 0xa5, 0xf1, 0x64, 0x49, 0x8e, 0xa0, 0xca, 0x12,
0x7e, 0x11, 0x46, 0xde, 0x8d, 0xaa, 0x2f, 0x2f, 0x23, 0xed, 0x4c, 0x47, 0xea, 0x7b, 0xc3, 0x00,
0xdd, 0xef, 0x30, 0x8e, 0xd9, 0x10, 0xe9, 0xdd, 0x5d, 0x4d, 0x84, 0x52, 0x1a, 0x9e, 0xd4, 0xc0,
0xd4, 0x77, 0xb4, 0x44, 0x4d, 0xcf, 0x9d, 0x77, 0x85, 0xcc, 0x79, 0x57, 0xa8, 0x01, 0x45, 0x27,
0x0c, 0x38, 0x06, 0x5c, 0xd3, 0x61, 0x22, 0x5a, 0xef, 0xa1, 0x28, 0xd3, 0xf4, 0xdc, 0xa9, 0x24,
0x53, 0x07, 0x31, 0x3f, 0xe5, 0x20, 0xd6, 0x08, 0x2a, 0x0a, 0xb2, 0x64, 0x34, 0x62, 0xd1, 0xf5,
0x54, 0x9a, 0xad, 0x09, 0xec, 0xf2, 0xad, 0x50, 0x47, 0x50, 0x70, 0x2e, 0x7a, 0x2d, 0xf2, 0x73,
0x8e, 0x6a, 0xfd, 0x61, 0x42, 0x4d, 0xe6, 0xa3, 0xc8, 0x23, 0x0f, 0x2f, 0x99, 0xff, 0xe0, 0xc4,
0xe9, 0xcd, 0x20, 0xce, 0x8b, 0x39, 0xc4, 0x49, 0xab, 0x7a, 0x50, 0xf2, 0xd0, 0x45, 0xe4, 0x59,
0x02, 0xf8, 0x67, 0x50, 0x08, 0xcf, 0xcf, 0x63, 0xe4, 0x1a, 0x63, 0x2d, 0x59, 0x6f, 0x61, 0xe3,
0xee, 0x09, 0xfa, 0x3c, 0x42, 0x36, 0xba, 0x17, 0xce, 0xb8, 0x1f, 0xee, 0x16, 0xf5, 0xcc, 0xbb,
0xd4, 0x73, 0xa1, 0xac, 0x8a, 0x44, 0x1f, 0x39, 0x2e, 0xa7, 0xdf, 0x27, 0x41, 0x61, 0x75, 0x80,
0xdc, 0xca, 0x32, 0x21, 0x61, 0x03, 0x8a, 0x23, 0xe5, 0xaf, 0x33, 0x4e, 0x44, 0xeb, 0x14, 0x1e,
0x65, 0x37, 0x7c, 0xa9, 0x3b, 0x79, 0x06, 0x35, 0xf9, 0xc8, 0xd9, 0x11, 0x3a, 0xe8, 0x5d, 0xa2,
0xab, 0x01, 0xad, 0x4a, 0x2d, 0xd5, 0x4a, 0x0b, 0x60, 0xad, 0xcf, 0x19, 0x8f, 0x29, 0xfe, 0x68,
0xfd, 0x6a, 0x40, 0x59, 0x08, 0x93, 0xe0, 0x5b, 0x00, 0x49, 0x8c, 0xae, 0x1d, 0x8f, 0x99, 0x93,
0x02, 0x28, 0x34, 0x7d, 0xa1, 0x20, 0x5f, 0xc2, 0x3a, 0xbb, 0x64, 0x9e, 0xcf, 0x06, 0x3e, 0x6a,
0x1f, 0x95, 0xa2, 0x96, 0xaa, 0x95, 0xe3, 0x33, 0xa8, 0xc9, 0x38, 0x29, 0x45, 0x75, 0x03, 0xab,
0x42, 0x9b, 0x92, 0x99, 0xec, 0xc2, 0xe3, 0x2c, 0x5e, 0xe6, 0xab, 0xc6, 0x2f, 0x49, 0x4d, 0xe9,
0x06, 0xeb, 0x3d, 0x54, 0xef, 0x20, 0x9c, 0x4e, 0x16, 0x23, 0x9b, 0x2c, 0x4b, 0x66, 0x91, 0xe0,
0x48, 0x32, 0xf0, 0x3d, 0xc7, 0xfe, 0x80, 0xd7, 0xfa, 0x09, 0x2a, 0x29, 0xcd, 0xb7, 0x78, 0x6d,
0xd5, 0xa0, 0xd2, 0x65, 0xf1, 0xc5, 0x20, 0x64, 0x91, 0x2b, 0x10, 0xfa, 0xc7, 0x80, 0x5a, 0xaa,
0x90, 0xb8, 0x91, 0xcf, 0xa1, 0x38, 0x99, 0x1d, 0xaa, 0x03, 0x85, 0x40, 0x0e, 0x09, 0xf2, 0x15,
0xd4, 0xa5, 0xc1, 0x09, 0x83, 0x00, 0xe5, 0x30, 0x8e, 0x35, 0x3e, 0xeb, 0x42, 0xff, 0x4d, 0xa6,
0x16, 0x5d, 0x64, 0xae, 0x1b, 0x61, 0x1c, 0xcb, 0x12, 0x4a, 0x74, 0x22, 0x92, 0xd7, 0xb0, 0x1a,
0x8b, 0x34, 0x12, 0x85, 0xf2, 0xfe, 0xd6, 0x0c, 0x8e, 0x65, 0x0d, 0xa3, 0xca, 0x97, 0x6c, 0x03,
0x64, 0x49, 0xe5, 0xa7, 0x64, 0x8d, 0xde, 0xd2, 0x90, 0x3d, 0x28, 0x24, 0x63, 0xee, 0x8d, 0x50,
0x7e, 0x49, 0xca, 0xfb, 0x9b, 0x1d, 0xf5, 0x03, 0xec, 0x4c, 0x7e, 0x80, 0x9d, 0xae, 0xfe, 0x01,
0x52, 0xed, 0xb8, 0xff, 0x77, 0x1e, 0xea, 0x19, 0xfb, 0xa8, 0x4c, 0x4d, 0xba, 0xb0, 0x2a, 0x75,
0x64, 0x73, 0xce, 0x9b, 0xd2, 0x73, 0x9b, 0xdb, 0xf3, 0xe6, 0x94, 0x2a, 0xd9, 0xca, 0x91, 0x77,
0xb0, 0xa6, 0x6f, 0x2e, 0x92, 0xd6, 0xb2, 0xc7, 0xa9, 0xf9, 0x7c, 0x99, 0x87, 0xba, 0xfc, 0x56,
0xae, 0x6d, 0xbc, 0x32, 0xc8, 0x31, 0xac, 0xaa, 0x11, 0xfd, 0x64, 0xd1, 0xb8, 0x6c, 0x3e, 0x5d,
0x64, 0x4d, 0x2b, 0x6d, 0x1b, 0xe4, 0x2d, 0x14, 0xf4, 0xa3, 0xb0, 0x35, 0x67, 0x8b, 0x32, 0x37,
0xbf, 0x58, 0x68, 0xce, 0x0e, 0xdf, 0x15, 0x05, 0x8a, 0x9e, 0x35, 0x67, 0x77, 0x56, 0xdc, 0xcb,
0xe6, 0xe2, 0xae, 0x5b, 0x39, 0xf2, 0x3d, 0x94, 0x52, 0x56, 0x92, 0x19, 0x88, 0xdf, 0xe6, 0x70,
0xb3, 0xb5, 0xc0, 0x2e, 0x53, 0x5a, 0xb9, 0x57, 0xc6, 0xe1, 0xca, 0x3b, 0x73, 0x3c, 0x18, 0x14,
0x24, 0x23, 0x5e, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x7c, 0xff, 0x5a, 0x5f, 0x0c, 0x00,
0x00,
}

View File

@ -42,11 +42,11 @@ message PayerBandwidthAllocation { // Payer refers to satellite
string serial_number = 5; // Unique serial number
Action action = 6; // GET or PUT
int64 created_unix_sec = 7; // Unix timestamp for when PayerbandwidthAllocation was created
bytes pub_key = 8; // Renter Public Key
}
bytes signature = 1; // Seralized Data signed by Satellite
bytes data = 2; // Serialization of above Data Struct
repeated bytes certs = 1; // Satellite certificate chain
bytes signature = 2; // Proof that the data was signed by the Satellite
bytes data = 3; // Serialization of above Data Struct
}
message RenterBandwidthAllocation { // Renter refers to uplink
@ -56,8 +56,9 @@ message RenterBandwidthAllocation { // Renter refers to uplink
bytes storage_node_id = 3 [(gogoproto.customtype) = "NodeID", (gogoproto.nullable) = false]; // Storage Node Identity
}
bytes signature = 1; // Seralized Data signed by Uplink
bytes data = 2; // Serialization of above Data Struct
repeated bytes certs = 1; // Uplink certificate chain
bytes signature = 2; // Proof that the data was signed by the Uplink
bytes data = 3; // Serialization of above Data Struct
}
message PieceStore {

View File

@ -5,7 +5,6 @@ package psclient
import (
"bufio"
"crypto"
"crypto/ecdsa"
"flag"
"fmt"
@ -19,6 +18,7 @@ import (
"golang.org/x/net/context"
"storj.io/storj/internal/memory"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/ranger"
"storj.io/storj/pkg/storj"
@ -55,9 +55,9 @@ type Client interface {
type PieceStore struct {
closeFunc func() error // function that closes the transport connection
client pb.PieceStoreRoutesClient // PieceStore for interacting with Storage Node
prikey crypto.PrivateKey // Uplink private key
selfID *identity.FullIdentity // This client's (an uplink) identity
bandwidthMsgSize int // max bandwidth message size in bytes
nodeID storj.NodeID // Storage node being connected to
remoteID storj.NodeID // Storage node being connected to
}
// NewPSClient initilizes a piecestore client
@ -80,13 +80,13 @@ func NewPSClient(ctx context.Context, tc transport.Client, n *pb.Node, bandwidth
closeFunc: conn.Close,
client: pb.NewPieceStoreRoutesClient(conn),
bandwidthMsgSize: bandwidthMsgSize,
prikey: tc.Identity().Key,
nodeID: n.Id,
selfID: tc.Identity(),
remoteID: n.Id,
}, nil
}
// NewCustomRoute creates new PieceStore with custom client interface
func NewCustomRoute(client pb.PieceStoreRoutesClient, target *pb.Node, bandwidthMsgSize int, prikey crypto.PrivateKey) (*PieceStore, error) {
func NewCustomRoute(client pb.PieceStoreRoutesClient, target *pb.Node, bandwidthMsgSize int, selfID *identity.FullIdentity) (*PieceStore, error) {
target.Type.DPanicOnInvalid("new custom route")
if bandwidthMsgSize < 0 || bandwidthMsgSize > maxBandwidthMsgSize.Int() {
return nil, ClientError.New("invalid Bandwidth Message Size: %v", bandwidthMsgSize)
@ -99,8 +99,8 @@ func NewCustomRoute(client pb.PieceStoreRoutesClient, target *pb.Node, bandwidth
return &PieceStore{
client: client,
bandwidthMsgSize: bandwidthMsgSize,
prikey: prikey,
nodeID: target.Id,
selfID: selfID,
remoteID: target.Id,
}, nil
}
@ -185,10 +185,13 @@ func (ps *PieceStore) Delete(ctx context.Context, id PieceID, authorization *pb.
// sign a message using the clients private key
func (ps *PieceStore) sign(msg []byte) (signature []byte, err error) {
if ps.prikey == nil {
if ps.selfID == nil || ps.selfID.Key == nil {
return nil, ClientError.New("failed to sign msg: Private Key not Set")
}
// use c.pkey to sign msg
return cryptopasta.Sign(msg, ps.prikey.(*ecdsa.PrivateKey))
return cryptopasta.Sign(msg, ps.selfID.Key.(*ecdsa.PrivateKey))
}
//certs returns this uplink's certificates
func (ps *PieceStore) certs() [][]byte {
return ps.selfID.ChainRaw()
}

View File

@ -5,9 +5,6 @@ package psclient
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
"io"
"io/ioutil"
@ -16,6 +13,8 @@ import (
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"storj.io/storj/internal/testcontext"
"storj.io/storj/internal/testidentity"
"storj.io/storj/internal/teststorj"
"storj.io/storj/pkg/pb"
)
@ -45,8 +44,10 @@ func TestPieceRanger(t *testing.T) {
} {
errTag := fmt.Sprintf("Test case #%d", i)
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
assert.Nil(t, err)
ctx := testcontext.New(t)
defer ctx.Cleanup()
id, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err)
route := pb.NewMockPieceStoreRoutesClient(ctrl)
@ -74,8 +75,6 @@ func TestPieceRanger(t *testing.T) {
stream.EXPECT().Recv().Return(&pb.PieceRetrievalStream{}, io.EOF)
}
ctx := context.Background()
target := &pb.Node{
Address: &pb.NodeAddress{
Address: "",
@ -85,7 +84,7 @@ func TestPieceRanger(t *testing.T) {
Type: pb.NodeType_STORAGE,
}
target.Type.DPanicOnInvalid("pr test")
c, err := NewCustomRoute(route, target, 32*1024, priv)
c, err := NewCustomRoute(route, target, 32*1024, id)
assert.NoError(t, err)
rr, err := PieceRanger(ctx, c, stream, pid, &pb.PayerBandwidthAllocation{}, nil)
if assert.NoError(t, err, errTag) {
@ -108,6 +107,11 @@ func TestPieceRangerSize(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := testcontext.New(t)
defer ctx.Cleanup()
id, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err)
for i, tt := range []struct {
data string
size, offset, length int64
@ -134,9 +138,6 @@ func TestPieceRangerSize(t *testing.T) {
stream := pb.NewMockPieceStoreRoutes_RetrieveClient(ctrl)
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
assert.Nil(t, err)
if tt.offset >= 0 && tt.length > 0 && tt.offset+tt.length <= tt.size {
msg1 := &pb.PieceRetrieval{
PieceData: &pb.PieceRetrieval_PieceData{
@ -165,7 +166,7 @@ func TestPieceRangerSize(t *testing.T) {
Type: pb.NodeType_STORAGE,
}
target.Type.DPanicOnInvalid("pr test 2")
c, err := NewCustomRoute(route, target, 32*1024, priv)
c, err := NewCustomRoute(route, target, 32*1024, id)
assert.NoError(t, err)
rr := PieceRangerSize(c, stream, pid, tt.size, &pb.PayerBandwidthAllocation{}, nil)
assert.Equal(t, tt.size, rr.Size(), errTag)

View File

@ -25,13 +25,13 @@ type StreamWriter struct {
// Write Piece data to a piece store server upload stream
func (s *StreamWriter) Write(b []byte) (int, error) {
updatedAllocation := s.totalWritten + int64(len(b))
allocationData := &pb.RenterBandwidthAllocation_Data{
renterBWA := &pb.RenterBandwidthAllocation_Data{
PayerAllocation: s.pba,
Total: updatedAllocation,
StorageNodeId: s.signer.nodeID,
StorageNodeId: s.signer.remoteID,
}
serializedAllocation, err := proto.Marshal(allocationData)
serializedAllocation, err := proto.Marshal(renterBWA)
if err != nil {
return 0, err
}
@ -44,7 +44,9 @@ func (s *StreamWriter) Write(b []byte) (int, error) {
msg := &pb.PieceStore{
PieceData: &pb.PieceStore_PieceData{Content: b},
BandwidthAllocation: &pb.RenterBandwidthAllocation{
Data: serializedAllocation, Signature: sig,
Data: serializedAllocation,
Signature: sig,
Certs: s.signer.certs(),
},
}
@ -93,6 +95,7 @@ func NewStreamReader(client *PieceStore, stream pb.PieceStoreRoutes_RetrieveClie
// TODO: make these flag/config-file configurable
trustLimit := int64(client.bandwidthMsgSize * 64)
sendThreshold := int64(client.bandwidthMsgSize * 8)
certs := client.certs()
// Send signed allocations to the piece store server
go func() {
@ -109,7 +112,7 @@ func NewStreamReader(client *PieceStore, stream pb.PieceStoreRoutes_RetrieveClie
allocationData := &pb.RenterBandwidthAllocation_Data{
PayerAllocation: pba,
Total: sr.allocated + allocate,
StorageNodeId: sr.client.nodeID,
StorageNodeId: sr.client.remoteID,
}
serializedAllocation, err := proto.Marshal(allocationData)
@ -128,6 +131,7 @@ func NewStreamReader(client *PieceStore, stream pb.PieceStoreRoutes_RetrieveClie
BandwidthAllocation: &pb.RenterBandwidthAllocation{
Signature: sig,
Data: serializedAllocation,
Certs: certs,
},
}

View File

@ -134,7 +134,7 @@ func (s *Server) retrieveData(ctx context.Context, stream pb.PieceStoreRoutes_Re
return
}
if err = s.verifySignature(ctx, alloc); err != nil {
if err = s.verifySignature(stream.Context(), alloc); err != nil {
allocationTracking.Fail(err)
return
}

View File

@ -5,7 +5,6 @@ package psserver
import (
"crypto"
"crypto/ecdsa"
"crypto/hmac"
"crypto/sha512"
"errors"
@ -17,19 +16,17 @@ import (
"time"
"github.com/golang/protobuf/ptypes"
"github.com/gtank/cryptopasta"
"github.com/mr-tron/base58/base58"
"github.com/zeebo/errs"
"go.uber.org/zap"
"golang.org/x/net/context"
"storj.io/storj/pkg/auth"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/kademlia"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/peertls"
pstore "storj.io/storj/pkg/piecestore"
"storj.io/storj/pkg/piecestore/psserver/psdb"
"storj.io/storj/pkg/provider"
"storj.io/storj/pkg/storj"
)
@ -262,12 +259,10 @@ func (s *Server) Dashboard(in *pb.DashboardReq, stream pb.PieceStoreRoutes_Dashb
// Delete -- Delete data by Id from piecestore
func (s *Server) Delete(ctx context.Context, in *pb.PieceDelete) (*pb.PieceDeleteSummary, error) {
s.log.Debug("Deleting", zap.String("Piece ID", fmt.Sprint(in.GetId())))
authorization := in.GetAuthorization()
if err := s.verifier(authorization); err != nil {
return nil, ServerError.Wrap(err)
}
id, err := getNamespacedPieceID([]byte(in.GetId()), getNamespace(authorization))
if err != nil {
return nil, err
@ -285,28 +280,43 @@ func (s *Server) deleteByID(id string) error {
if err := s.storage.Delete(id); err != nil {
return err
}
if err := s.DB.DeleteTTLByID(id); err != nil {
return err
}
return nil
}
func (s *Server) verifySignature(ctx context.Context, ba *pb.RenterBandwidthAllocation) error {
func (s *Server) verifySignature(ctx context.Context, rba *pb.RenterBandwidthAllocation) error {
// TODO(security): detect replay attacks
pi, err := provider.PeerIdentityFromContext(ctx)
_, pba, pbad, err := rba.Unpack()
if err != nil {
return err
}
k, ok := pi.Leaf.PublicKey.(*ecdsa.PublicKey)
if !ok {
return peertls.ErrUnsupportedKey.New("%T", pi.Leaf.PublicKey)
//verify message content
pi, err := identity.PeerIdentityFromContext(ctx)
if err != nil || pbad.UplinkId != pi.ID {
return auth.BadID.New("Uplink Node ID: %s vs %s", pbad.UplinkId, pi.ID)
}
if ok := cryptopasta.Verify(ba.GetData(), ba.GetSignature(), k); !ok {
return ServerError.New("failed to verify Signature")
//todo: use whitelist for uplinks?
//todo: use whitelist for satellites?
switch {
case len(pbad.SerialNumber) == 0:
return pb.Payer.Wrap(pb.Missing.New("serial"))
case pbad.SatelliteId.IsZero():
return pb.Payer.Wrap(pb.Missing.New("satellite id"))
case pbad.UplinkId.IsZero():
return pb.Payer.Wrap(pb.Missing.New("uplink id"))
}
exp := time.Unix(pbad.GetExpirationUnixSec(), 0).UTC()
if exp.Before(time.Now().UTC()) {
return pb.Payer.Wrap(auth.Expired.New("%v vs %v", exp, time.Now().UTC()))
}
//verify message crypto
if err := auth.VerifyMsg(rba, pbad.UplinkId); err != nil {
return pb.Renter.Wrap(err)
}
if err := auth.VerifyMsg(pba, pbad.SatelliteId); err != nil {
return pb.Payer.Wrap(err)
}
return nil
}

View File

@ -4,12 +4,9 @@
package psserver
import (
"crypto"
"crypto/ecdsa"
"fmt"
"io"
"io/ioutil"
"log"
"math"
"net"
"os"
@ -17,9 +14,9 @@ import (
"runtime"
"strings"
"testing"
"time"
"github.com/gogo/protobuf/proto"
"github.com/gtank/cryptopasta"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/assert"
"github.com/zeebo/errs"
@ -29,37 +26,29 @@ import (
"storj.io/storj/internal/testcontext"
"storj.io/storj/internal/testidentity"
"storj.io/storj/internal/teststorj"
"storj.io/storj/pkg/bwagreement/test"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
pstore "storj.io/storj/pkg/piecestore"
"storj.io/storj/pkg/piecestore/psserver/psdb"
"storj.io/storj/pkg/server"
"storj.io/storj/pkg/storj"
)
func (TS *TestServer) writeFile(pieceID string) error {
file, err := TS.s.storage.Writer(pieceID)
if err != nil {
return err
}
_, err = file.Write([]byte("xyzwq"))
return errs.Combine(err, file.Close())
}
func TestPiece(t *testing.T) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
TS := NewTestServer(t, []storj.NodeID{})
defer TS.Stop()
snID, upID := newTestID(ctx, t), newTestID(ctx, t)
s, c, cleanup := NewTest(ctx, t, snID, upID, []storj.NodeID{})
defer cleanup()
if err := TS.writeFile("11111111111111111111"); err != nil {
if err := writeFile(s, "11111111111111111111"); err != nil {
t.Errorf("Error: %v\nCould not create test piece", err)
return
}
defer func() { _ = TS.s.storage.Delete("11111111111111111111") }()
defer func() { _ = s.storage.Delete("11111111111111111111") }()
// set up test cases
tests := []struct {
@ -85,7 +74,7 @@ func TestPiece(t *testing.T) {
size: 5,
expiration: 9999999999,
err: fmt.Sprintf("rpc error: code = Unknown desc = stat %s: no such file or directory", func() string {
path, _ := TS.s.storage.PiecePath("22222222222222222222")
path, _ := s.storage.PiecePath("22222222222222222222")
return path
}()),
},
@ -102,16 +91,16 @@ func TestPiece(t *testing.T) {
assert := assert.New(t)
// simulate piece TTL entry
_, err := TS.s.DB.DB.Exec(fmt.Sprintf(`INSERT INTO ttl (id, created, expires) VALUES ("%s", "%d", "%d")`, tt.id, 1234567890, tt.expiration))
_, err := s.DB.DB.Exec(fmt.Sprintf(`INSERT INTO ttl (id, created, expires) VALUES ("%s", "%d", "%d")`, tt.id, 1234567890, tt.expiration))
assert.NoError(err)
defer func() {
_, err := TS.s.DB.DB.Exec(fmt.Sprintf(`DELETE FROM ttl WHERE id="%s"`, tt.id))
_, err := s.DB.DB.Exec(fmt.Sprintf(`DELETE FROM ttl WHERE id="%s"`, tt.id))
assert.NoError(err)
}()
req := &pb.PieceId{Id: tt.id}
resp, err := TS.c.Piece(ctx, req)
resp, err := c.Piece(ctx, req)
if tt.err != "" {
assert.NotNil(err)
@ -133,20 +122,19 @@ func TestPiece(t *testing.T) {
}
func TestRetrieve(t *testing.T) {
t.Skip("broken test")
ctx := testcontext.New(t)
defer ctx.Cleanup()
TS := NewTestServer(t, []storj.NodeID{})
defer TS.Stop()
snID, upID := newTestID(ctx, t), newTestID(ctx, t)
s, c, cleanup := NewTest(ctx, t, snID, upID, []storj.NodeID{})
defer cleanup()
if err := TS.writeFile("11111111111111111111"); err != nil {
if err := writeFile(s, "11111111111111111111"); err != nil {
t.Errorf("Error: %v\nCould not create test piece", err)
return
}
defer func() { _ = TS.s.storage.Delete("11111111111111111111") }()
defer func() { _ = s.storage.Delete("11111111111111111111") }()
// set up test cases
tests := []struct {
@ -182,7 +170,7 @@ func TestRetrieve(t *testing.T) {
respSize: 3,
allocSize: 3,
offset: 0,
content: []byte("but"),
content: []byte("xyz"),
err: "",
},
{ // should successfully retrieve data
@ -211,7 +199,7 @@ func TestRetrieve(t *testing.T) {
offset: 0,
content: []byte("xyzwq"),
err: fmt.Sprintf("rpc error: code = Unknown desc = retrieve error: stat %s: no such file or directory", func() string {
path, _ := TS.s.storage.PiecePath("22222222222222222222")
path, _ := s.storage.PiecePath("22222222222222222222")
return path
}()),
},
@ -221,7 +209,7 @@ func TestRetrieve(t *testing.T) {
respSize: 4,
allocSize: 5,
offset: 1,
content: []byte("utts"),
content: []byte("yzwq"),
err: "",
},
{ // server should return expected content with reduced reqSize
@ -230,7 +218,7 @@ func TestRetrieve(t *testing.T) {
respSize: 4,
allocSize: 5,
offset: 0,
content: []byte("butt"),
content: []byte("xyzw"),
err: "",
},
}
@ -238,13 +226,16 @@ func TestRetrieve(t *testing.T) {
for _, tt := range tests {
t.Run("should return expected PieceRetrievalStream values", func(t *testing.T) {
assert := assert.New(t)
stream, err := TS.c.Retrieve(ctx)
stream, err := c.Retrieve(ctx)
assert.NoError(err)
// send piece database
err = stream.Send(&pb.PieceRetrieval{PieceData: &pb.PieceRetrieval_PieceData{Id: tt.id, PieceSize: tt.reqSize, Offset: tt.offset}})
assert.NoError(err)
pba, err := test.GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, snID, upID, time.Hour)
assert.NoError(err)
totalAllocated := int64(0)
var data string
var totalRetrieved = int64(0)
@ -253,20 +244,12 @@ func TestRetrieve(t *testing.T) {
// Send bandwidth bandwidthAllocation
totalAllocated += tt.allocSize
ba := pb.RenterBandwidthAllocation{
Data: serializeData(&pb.RenterBandwidthAllocation_Data{
PayerAllocation: &pb.PayerBandwidthAllocation{},
Total: totalAllocated,
}),
}
s, err := cryptopasta.Sign(ba.Data, TS.k.(*ecdsa.PrivateKey))
rba, err := test.GenerateRenterBandwidthAllocation(pba, snID.ID, upID, totalAllocated)
assert.NoError(err)
ba.Signature = s
err = stream.Send(
&pb.PieceRetrieval{
BandwidthAllocation: &ba,
BandwidthAllocation: rba,
},
)
assert.NoError(err)
@ -300,7 +283,7 @@ func TestStore(t *testing.T) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
satID := teststorj.NodeIDFromString("satelliteid")
satID := newTestID(ctx, t)
tests := []struct {
id string
@ -314,7 +297,7 @@ func TestStore(t *testing.T) {
}{
{ // should successfully store data with no approved satellites
id: "99999999999999999999",
satelliteID: satID,
satelliteID: satID.ID,
whitelist: []storj.NodeID{},
ttl: 9999999999,
content: []byte("xyzwq"),
@ -324,8 +307,8 @@ func TestStore(t *testing.T) {
},
{ // should err with invalid id length
id: "butts",
satelliteID: satID,
whitelist: []storj.NodeID{satID},
satelliteID: satID.ID,
whitelist: []storj.NodeID{satID.ID},
ttl: 9999999999,
content: []byte("xyzwq"),
message: "",
@ -334,8 +317,8 @@ func TestStore(t *testing.T) {
},
{ // should err with piece ID not specified
id: "",
satelliteID: satID,
whitelist: []storj.NodeID{satID},
satelliteID: satID.ID,
whitelist: []storj.NodeID{satID.ID},
ttl: 9999999999,
content: []byte("xyzwq"),
message: "",
@ -346,41 +329,27 @@ func TestStore(t *testing.T) {
for _, tt := range tests {
t.Run("should return expected PieceStoreSummary values", func(t *testing.T) {
TS := NewTestServer(t, tt.whitelist)
db := TS.s.DB.DB
defer TS.Stop()
snID, upID := newTestID(ctx, t), newTestID(ctx, t)
s, c, cleanup := NewTest(ctx, t, snID, upID, []storj.NodeID{})
defer cleanup()
db := s.DB.DB
assert := assert.New(t)
stream, err := TS.c.Store(ctx)
stream, err := c.Store(ctx)
assert.NoError(err)
// Write the buffer to the stream we opened earlier
err = stream.Send(&pb.PieceStore{PieceData: &pb.PieceStore_PieceData{Id: tt.id, ExpirationUnixSec: tt.ttl}})
assert.NoError(err)
pbad := &pb.PayerBandwidthAllocation_Data{
SatelliteId: tt.satelliteID,
UplinkId: teststorj.NodeIDFromString("uplinkid"),
Action: pb.PayerBandwidthAllocation_PUT,
}
pbaData, err := proto.Marshal(pbad)
assert.NoError(err)
pba := &pb.PayerBandwidthAllocation{Data: pbaData}
// Send Bandwidth Allocation Data
msg := &pb.PieceStore{
PieceData: &pb.PieceStore_PieceData{Content: tt.content},
BandwidthAllocation: &pb.RenterBandwidthAllocation{
Data: serializeData(&pb.RenterBandwidthAllocation_Data{
PayerAllocation: pba,
Total: int64(len(tt.content)),
}),
},
}
s, err := cryptopasta.Sign(msg.BandwidthAllocation.Data, TS.k.(*ecdsa.PrivateKey))
pba, err := test.GeneratePayerBandwidthAllocation(pb.PayerBandwidthAllocation_PUT, snID, upID, time.Hour)
assert.NoError(err)
msg.BandwidthAllocation.Signature = s
rba, err := test.GenerateRenterBandwidthAllocation(pba, snID.ID, upID, tt.totalReceived)
assert.NoError(err)
msg := &pb.PieceStore{
PieceData: &pb.PieceStore_PieceData{Content: tt.content},
BandwidthAllocation: rba,
}
// Write the buffer to the stream we opened earlier
err = stream.Send(msg)
if err != io.EOF && err != nil {
@ -390,11 +359,12 @@ func TestStore(t *testing.T) {
resp, err := stream.CloseAndRecv()
if tt.err != "" {
assert.NotNil(err)
assert.Equal(tt.err, err.Error())
assert.True(strings.HasPrefix(err.Error(), tt.err), "expected")
return
}
assert.NoError(err)
if !assert.NoError(err) {
t.Fatal(err)
}
defer func() {
_, err := db.Exec(fmt.Sprintf(`DELETE FROM ttl WHERE id="%s"`, tt.id))
@ -426,7 +396,9 @@ func TestStore(t *testing.T) {
}
err = rows.Err()
assert.NoError(err)
if !assert.NotNil(resp) {
t.Fatalf("resp is null")
}
assert.Equal(tt.message, resp.Message)
assert.Equal(tt.totalReceived, resp.TotalReceived)
})
@ -435,6 +407,8 @@ func TestStore(t *testing.T) {
func TestPbaValidation(t *testing.T) {
ctx := testcontext.New(t)
snID, upID := newTestID(ctx, t), newTestID(ctx, t)
satID1, satID2, satID3 := newTestID(ctx, t), newTestID(ctx, t), newTestID(ctx, t)
defer ctx.Cleanup()
tests := []struct {
@ -445,87 +419,59 @@ func TestPbaValidation(t *testing.T) {
err string
}{
{ // unapproved satellite id
satelliteID: teststorj.NodeIDFromString("bad-satellite"),
uplinkID: teststorj.NodeIDFromString("uplinkid"),
whitelist: []storj.NodeID{
teststorj.NodeIDFromString("satelliteid1"),
teststorj.NodeIDFromString("satelliteid2"),
teststorj.NodeIDFromString("satelliteid3"),
},
action: pb.PayerBandwidthAllocation_PUT,
err: "rpc error: code = Unknown desc = store error: Satellite ID not approved",
satelliteID: satID1.ID,
uplinkID: upID.ID,
whitelist: []storj.NodeID{satID1.ID, satID2.ID, satID3.ID},
action: pb.PayerBandwidthAllocation_PUT,
err: "rpc error: code = Unknown desc = store error: Satellite ID not approved",
},
{ // missing satellite id
satelliteID: storj.NodeID{},
uplinkID: teststorj.NodeIDFromString("uplinkid"),
whitelist: []storj.NodeID{
teststorj.NodeIDFromString("satelliteid1"),
teststorj.NodeIDFromString("satelliteid2"),
teststorj.NodeIDFromString("satelliteid3"),
},
action: pb.PayerBandwidthAllocation_PUT,
err: "rpc error: code = Unknown desc = store error: payer bandwidth allocation: missing satellite id",
uplinkID: upID.ID,
whitelist: []storj.NodeID{satID1.ID, satID2.ID, satID3.ID},
action: pb.PayerBandwidthAllocation_PUT,
err: "rpc error: code = Unknown desc = store error: payer bandwidth allocation: missing satellite id",
},
{ // missing uplink id
satelliteID: teststorj.NodeIDFromString("satelliteid1"),
satelliteID: satID1.ID,
uplinkID: storj.NodeID{},
whitelist: []storj.NodeID{
teststorj.NodeIDFromString("satelliteid1"),
teststorj.NodeIDFromString("satelliteid2"),
teststorj.NodeIDFromString("satelliteid3"),
},
action: pb.PayerBandwidthAllocation_PUT,
err: "rpc error: code = Unknown desc = store error: payer bandwidth allocation: missing uplink id",
whitelist: []storj.NodeID{satID1.ID, satID2.ID, satID3.ID},
action: pb.PayerBandwidthAllocation_PUT,
err: "rpc error: code = Unknown desc = store error: payer bandwidth allocation: missing uplink id",
},
{ // wrong action type
satelliteID: teststorj.NodeIDFromString("satelliteid1"),
uplinkID: teststorj.NodeIDFromString("uplinkid"),
whitelist: []storj.NodeID{
teststorj.NodeIDFromString("satelliteid1"),
teststorj.NodeIDFromString("satelliteid2"),
teststorj.NodeIDFromString("satelliteid3"),
},
action: pb.PayerBandwidthAllocation_GET,
err: "rpc error: code = Unknown desc = store error: payer bandwidth allocation: invalid action GET",
satelliteID: satID1.ID,
uplinkID: upID.ID,
whitelist: []storj.NodeID{satID1.ID, satID2.ID, satID3.ID},
action: pb.PayerBandwidthAllocation_GET,
err: "rpc error: code = Unknown desc = store error: payer bandwidth allocation: invalid action GET",
},
}
for _, tt := range tests {
t.Run("should validate payer bandwidth allocation struct", func(t *testing.T) {
TS := NewTestServer(t, tt.whitelist)
defer TS.Stop()
s, c, cleanup := NewTest(ctx, t, snID, upID, tt.whitelist)
defer cleanup()
assert := assert.New(t)
stream, err := TS.c.Store(ctx)
stream, err := c.Store(ctx)
assert.NoError(err)
//cleanup incase tests previously paniced
_ = s.storage.Delete("99999999999999999999")
// Write the buffer to the stream we opened earlier
err = stream.Send(&pb.PieceStore{PieceData: &pb.PieceStore_PieceData{Id: "99999999999999999999", ExpirationUnixSec: 9999999999}})
assert.NoError(err)
pbad := &pb.PayerBandwidthAllocation_Data{
SatelliteId: tt.satelliteID,
UplinkId: tt.uplinkID,
Action: tt.action,
}
pbaData, err := proto.Marshal(pbad)
assert.NoError(err)
pba := &pb.PayerBandwidthAllocation{Data: pbaData}
// Send Bandwidth Allocation Data
content := []byte("content")
msg := &pb.PieceStore{
PieceData: &pb.PieceStore_PieceData{Content: content},
BandwidthAllocation: &pb.RenterBandwidthAllocation{
Data: serializeData(&pb.RenterBandwidthAllocation_Data{
PayerAllocation: pba,
Total: int64(len(content)),
}),
},
}
s, err := cryptopasta.Sign(msg.BandwidthAllocation.Data, TS.k.(*ecdsa.PrivateKey))
pba, err := test.GeneratePayerBandwidthAllocation(tt.action, satID1, upID, time.Hour)
assert.NoError(err)
msg.BandwidthAllocation.Signature = s
rba, err := test.GenerateRenterBandwidthAllocation(pba, snID.ID, upID, int64(len(content)))
assert.NoError(err)
msg := &pb.PieceStore{
PieceData: &pb.PieceStore_PieceData{Content: content},
BandwidthAllocation: rba,
}
// Write the buffer to the stream we opened earlier
err = stream.Send(msg)
@ -549,10 +495,11 @@ func TestDelete(t *testing.T) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
TS := NewTestServer(t, []storj.NodeID{})
defer TS.Stop()
snID, upID := newTestID(ctx, t), newTestID(ctx, t)
s, c, cleanup := NewTest(ctx, t, snID, upID, []storj.NodeID{})
defer cleanup()
db := TS.s.DB.DB
db := s.DB.DB
// set up test cases
tests := []struct {
@ -582,7 +529,7 @@ func TestDelete(t *testing.T) {
assert := assert.New(t)
// simulate piece stored with storagenode
if err := TS.writeFile("11111111111111111111"); err != nil {
if err := writeFile(s, "11111111111111111111"); err != nil {
t.Errorf("Error: %v\nCould not create test piece", err)
return
}
@ -597,11 +544,11 @@ func TestDelete(t *testing.T) {
}()
defer func() {
assert.NoError(TS.s.storage.Delete("11111111111111111111"))
assert.NoError(s.storage.Delete("11111111111111111111"))
}()
req := &pb.PieceDelete{Id: tt.id}
resp, err := TS.c.Delete(ctx, req)
resp, err := c.Delete(ctx, req)
if tt.err != "" {
assert.Equal(tt.err, err.Error())
@ -612,7 +559,7 @@ func TestDelete(t *testing.T) {
assert.Equal(tt.message, resp.GetMessage())
// if test passes, check if file was indeed deleted
filePath, err := TS.s.storage.PiecePath(tt.id)
filePath, err := s.storage.PiecePath(tt.id)
assert.NoError(err)
if _, err = os.Stat(filePath); os.IsExist(err) {
t.Errorf("File not deleted")
@ -622,25 +569,20 @@ func TestDelete(t *testing.T) {
}
}
func newTestServerStruct(t *testing.T, ids []storj.NodeID) (*Server, func()) {
func NewTest(ctx context.Context, t *testing.T, snID, upID *identity.FullIdentity,
ids []storj.NodeID) (*Server, pb.PieceStoreRoutesClient, func()) {
//init ps server backend
tmp, err := ioutil.TempDir("", "storj-piecestore")
if err != nil {
log.Fatalf("failed temp-dir: %v", err)
}
assert.NoError(t, err)
tempDBPath := filepath.Join(tmp, "test.db")
tempDir := filepath.Join(tmp, "test-data", "3000")
storage := pstore.NewStorage(tempDir)
psDB, err := psdb.Open(context.TODO(), storage, tempDBPath)
if err != nil {
t.Fatalf("failed open psdb: %v", err)
}
psDB, err := psdb.Open(ctx, storage, tempDBPath)
assert.NoError(t, err)
verifier := func(authorization *pb.SignedMessage) error {
return nil
}
server := &Server{
psServer := &Server{
log: zaptest.NewLogger(t),
storage: storage,
DB: psDB,
@ -649,95 +591,45 @@ func newTestServerStruct(t *testing.T, ids []storj.NodeID) (*Server, func()) {
totalBwAllocated: math.MaxInt64,
whitelist: ids,
}
return server, func() {
if serr := server.Stop(context.TODO()); serr != nil {
t.Fatal(serr)
}
// TODO:fix this error check
_ = os.RemoveAll(tmp)
// if err := os.RemoveAll(tmp); err != nil {
// t.Fatal(err)
// }
//init ps server grpc
listener, err := net.Listen("tcp", "127.0.0.1:0")
assert.NoError(t, err)
publicConfig := server.Config{Address: "127.0.0.1:0"}
publicOptions, err := server.NewOptions(snID, publicConfig)
assert.NoError(t, err)
grpcServer, err := server.NewServer(publicOptions, listener, nil)
assert.NoError(t, err)
pb.RegisterPieceStoreRoutesServer(grpcServer.GRPC(), psServer)
go func() { assert.NoError(t, grpcServer.Run(ctx)) }()
//init client
co, err := upID.DialOption(storj.NodeID{})
assert.NoError(t, err)
conn, err := grpc.Dial(listener.Addr().String(), co)
assert.NoError(t, err)
psClient := pb.NewPieceStoreRoutesClient(conn)
//cleanup callback
cleanup := func() {
assert.NoError(t, conn.Close())
assert.NoError(t, psServer.Close())
assert.NoError(t, psServer.Stop(ctx))
assert.NoError(t, os.RemoveAll(tmp))
}
return psServer, psClient, cleanup
}
func connect(addr string, o ...grpc.DialOption) (pb.PieceStoreRoutesClient, *grpc.ClientConn) {
conn, err := grpc.Dial(addr, o...)
func newTestID(ctx context.Context, t *testing.T) *identity.FullIdentity {
id, err := testidentity.NewTestIdentity(ctx)
if err != nil {
log.Fatalf("did not connect: %v", err)
t.Fatal(err)
}
c := pb.NewPieceStoreRoutesClient(conn)
return c, conn
return id
}
type TestServer struct {
s *Server
scleanup func()
grpcs *grpc.Server
conn *grpc.ClientConn
c pb.PieceStoreRoutesClient
k crypto.PrivateKey
}
func NewTestServer(t *testing.T, ids []storj.NodeID) *TestServer {
check := func(e error) {
if !assert.NoError(t, e) {
t.Fail()
}
}
caS, err := testidentity.NewTestCA(context.Background())
check(err)
fiS, err := caS.NewIdentity()
check(err)
so, err := fiS.ServerOption()
check(err)
caC, err := testidentity.NewTestCA(context.Background())
check(err)
fiC, err := caC.NewIdentity()
check(err)
co, err := fiC.DialOption(storj.NodeID{})
check(err)
s, cleanup := newTestServerStruct(t, ids)
grpcs := grpc.NewServer(so)
k, ok := fiC.Key.(*ecdsa.PrivateKey)
assert.True(t, ok)
ts := &TestServer{s: s, scleanup: cleanup, grpcs: grpcs, k: k}
addr := ts.start()
ts.c, ts.conn = connect(addr, co)
return ts
}
func (TS *TestServer) start() (addr string) {
lis, err := net.Listen("tcp", "127.0.0.1:0")
func writeFile(s *Server, pieceID string) error {
file, err := s.storage.Writer(pieceID)
if err != nil {
log.Fatalf("failed to listen: %v", err)
return err
}
pb.RegisterPieceStoreRoutesServer(TS.grpcs, TS.s)
go func() {
if err := TS.grpcs.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}()
return lis.Addr().String()
}
func (TS *TestServer) Stop() {
if err := TS.conn.Close(); err != nil {
panic(err)
}
TS.grpcs.Stop()
TS.scleanup()
}
func serializeData(ba *pb.RenterBandwidthAllocation_Data) []byte {
data, _ := proto.Marshal(ba)
return data
_, err = file.Write([]byte("xyzwq"))
return errs.Combine(err, file.Close())
}

View File

@ -51,6 +51,8 @@ const IDLength = 20
// Errors
var (
Error = errs.Class("piecestore error")
MkDir = errs.Class("piecestore MkdirAll")
Open = errs.Class("piecestore OpenFile")
)
// PiecePath creates piece storage path from id and dir
@ -58,7 +60,6 @@ func (storage *Storage) PiecePath(pieceID string) (string, error) {
if len(pieceID) < IDLength {
return "", Error.New("invalid id length")
}
folder1, folder2, filename := pieceID[0:2], pieceID[2:4], pieceID[4:]
return filepath.Join(storage.dir, folder1, folder2, filename), nil
}
@ -69,16 +70,13 @@ func (storage *Storage) Writer(pieceID string) (io.WriteCloser, error) {
if err != nil {
return nil, err
}
if err = os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return nil, Error.Wrap(err)
return nil, MkDir.Wrap(err)
}
file, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600)
if err != nil {
return nil, Error.Wrap(err)
return nil, Open.Wrap(err)
}
return file, nil
}
@ -88,30 +86,24 @@ func (storage *Storage) Reader(ctx context.Context, pieceID string, offset int64
if err != nil {
return nil, err
}
info, err := os.Stat(path)
if err != nil {
return nil, err
}
if offset >= info.Size() || offset < 0 {
return nil, Error.New("invalid offset: %v", offset)
}
if length <= -1 {
length = info.Size()
}
// If trying to read past the end of the file, just read to the end
if info.Size() < offset+length {
length = info.Size() - offset
}
rr, err := ranger.FileRanger(path)
if err != nil {
return nil, err
}
return rr.Range(ctx, offset, length)
}

View File

@ -5,8 +5,6 @@ package pointerdb
import (
"context"
"crypto/ecdsa"
"crypto/x509"
"time"
"github.com/gogo/protobuf/proto"
@ -15,7 +13,6 @@ import (
"storj.io/storj/pkg/auth"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/peertls"
)
// AllocationSigner structure
@ -38,21 +35,10 @@ func (allocation *AllocationSigner) PayerBandwidthAllocation(ctx context.Context
return nil, Error.New("missing peer identity")
}
pk, ok := peerIdentity.Leaf.PublicKey.(*ecdsa.PublicKey)
if !ok {
return nil, peertls.ErrUnsupportedKey.New("%T", peerIdentity.Leaf.PublicKey)
}
pubbytes, err := x509.MarshalPKIXPublicKey(pk)
if err != nil {
return nil, err
}
serialNum, err := uuid.New()
if err != nil {
return nil, err
}
created := time.Now().Unix()
// convert ttl from days to seconds
@ -66,7 +52,6 @@ func (allocation *AllocationSigner) PayerBandwidthAllocation(ctx context.Context
ExpirationUnixSec: created + int64(ttl),
Action: action,
SerialNumber: serialNum.String(),
PubKey: pubbytes,
}
data, err := proto.Marshal(pbad)
@ -77,5 +62,6 @@ func (allocation *AllocationSigner) PayerBandwidthAllocation(ctx context.Context
if err != nil {
return nil, err
}
return &pb.PayerBandwidthAllocation{Signature: signature, Data: data}, nil
certs := allocation.satelliteIdentity.ChainRaw()
return &pb.PayerBandwidthAllocation{Signature: signature, Data: data, Certs: certs}, nil
}

View File

@ -4,6 +4,7 @@
package storj
import (
"crypto/sha256"
"math/bits"
"github.com/btcsuite/btcutil/base58"
@ -21,7 +22,7 @@ var (
)
// NodeID is a unique node identifier
type NodeID [32]byte
type NodeID [sha256.Size]byte
// NodeIDList is a slice of NodeIDs (implements sort)
type NodeIDList []NodeID

View File

@ -289,7 +289,8 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB, config *Config) (*
}
{ // setup agreements
peer.Agreements.Endpoint = bwagreement.NewServer(peer.DB.BandwidthAgreement(), peer.Log.Named("agreements"), peer.Identity.Leaf.PublicKey)
bwServer := bwagreement.NewServer(peer.DB.BandwidthAgreement(), peer.Log.Named("agreements"), peer.Identity.ID)
peer.Agreements.Endpoint = bwServer
pb.RegisterBandwidthServer(peer.Public.Server.GRPC(), peer.Agreements.Endpoint)
}