// Copyright (C) 2018 Storj Labs, Inc. // See LICENSE for copying information. package test import ( "context" "crypto" "crypto/ecdsa" "crypto/x509" "flag" "log" "net" "os" "testing" "time" "github.com/gogo/protobuf/proto" "github.com/gtank/cryptopasta" "github.com/stretchr/testify/assert" "github.com/zeebo/errs" "go.uber.org/zap" "google.golang.org/grpc" "storj.io/storj/internal/identity" "storj.io/storj/internal/teststorj" "storj.io/storj/pkg/bwagreement" "storj.io/storj/pkg/pb" "storj.io/storj/pkg/storj" "storj.io/storj/satellite/satellitedb" ) type testServer struct { S *bwagreement.Server Grpcs *grpc.Server Conn *grpc.ClientConn C pb.BandwidthClient K crypto.PrivateKey } func newTestServer(t *testing.T) *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 := newTestServerStruct(t, fiC.Key) grpcs := grpc.NewServer(so) k, ok := fiC.Key.(*ecdsa.PrivateKey) assert.True(t, ok) ts := &testServer{S: s, Grpcs: grpcs, K: k} addr := ts.Start() ts.C, ts.Conn = connect(addr, co) return ts } const ( // this connstring is expected to work under the storj-test docker-compose instance defaultPostgresConn = "postgres://storj:storj-pass@test-postgres/teststorj?sslmode=disable" ) var ( // for travis build support testPostgres = flag.String("postgres-test-db", os.Getenv("STORJ_POSTGRES_TEST"), "PostgreSQL test database connection string") ) func newTestServerStruct(t *testing.T, k crypto.PrivateKey) *bwagreement.Server { if *testPostgres == "" { t.Skipf("postgres flag missing, example:\n-postgres-test-db=%s", defaultPostgresConn) } db, err := satellitedb.NewDB(*testPostgres) if err != nil { t.Fatalf("Failed to initialize master db for test server: %+v", err) } err = db.CreateTables() if err != nil { t.Fatalf("Failed to create master db tables: %+v", err) } p, _ := k.(*ecdsa.PrivateKey) return bwagreement.NewServer(db.BandwidthAgreement(), zap.NewNop(), &p.PublicKey) } func (TS *testServer) Start() (addr string) { lis, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { log.Fatalf("failed to listen: %v", err) } pb.RegisterBandwidthServer(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 connect(addr string, o ...grpc.DialOption) (pb.BandwidthClient, *grpc.ClientConn) { conn, err := grpc.Dial(addr, o...) if err != nil { log.Fatalf("did not connect: %v", err) } c := pb.NewBandwidthClient(conn) return c, conn } //GeneratePayerBandwidthAllocation creates a signed PayerBandwidthAllocation from a PayerBandwidthAllocation_Action func GeneratePayerBandwidthAllocation(action pb.PayerBandwidthAllocation_Action, satelliteKey crypto.PrivateKey) (*pb.PayerBandwidthAllocation, error) { satelliteKeyEcdsa, ok := satelliteKey.(*ecdsa.PrivateKey) if !ok { return nil, errs.New("Satellite Private Key is not a valid *ecdsa.PrivateKey") } // Generate PayerBandwidthAllocation_Data data, _ := proto.Marshal( &pb.PayerBandwidthAllocation_Data{ SatelliteId: teststorj.NodeIDFromString("SatelliteID"), UplinkId: teststorj.NodeIDFromString("UplinkID"), ExpirationUnixSec: time.Now().Add(time.Hour * 24 * 10).Unix(), SerialNumber: "SerialNumber", Action: action, CreatedUnixSec: time.Now().Unix(), }, ) // 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) } // Combine Signature and Data for PayerBandwidthAllocation return &pb.PayerBandwidthAllocation{ Data: data, Signature: s, }, nil } //GenerateRenterBandwidthAllocation creates a signed RenterBandwidthAllocation from a PayerBandwidthAllocation func GenerateRenterBandwidthAllocation(pba *pb.PayerBandwidthAllocation, 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") } pubbytes, err := x509.MarshalPKIXPublicKey(&uplinkKeyEcdsa.PublicKey) if err != nil { return nil, errs.New("Could not generate byte array from Uplink Public key: %+v", err) } // Generate RenterBandwidthAllocation_Data data, _ := proto.Marshal( &pb.RenterBandwidthAllocation_Data{ PayerAllocation: pba, PubKey: pubbytes, // TODO: Take this out. It will be kept in a database on the satellite StorageNodeId: teststorj.NodeIDFromString("StorageNodeID"), Total: int64(666), }, ) // 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) } // Combine Signature and Data for RenterBandwidthAllocation return &pb.RenterBandwidthAllocation{ Signature: s, Data: data, }, nil } func (TS *testServer) stop() { if err := TS.Conn.Close(); err != nil { panic(err) } TS.Grpcs.Stop() }