2020-07-24 19:57:11 +01:00
|
|
|
// Copyright (C) 2020 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package orders
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/rand"
|
|
|
|
"encoding/binary"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
|
|
|
|
"storj.io/common/pb"
|
|
|
|
"storj.io/common/signing"
|
|
|
|
"storj.io/common/storj"
|
2020-07-24 18:13:15 +01:00
|
|
|
"storj.io/storj/satellite/metainfo/metabase"
|
2020-07-24 19:57:11 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// ErrSigner is default error class for Signer.
|
|
|
|
var ErrSigner = errs.Class("signer")
|
|
|
|
|
|
|
|
// Signer implements signing of order limits.
|
|
|
|
type Signer struct {
|
|
|
|
// TODO: should this be a ref to the necessary pieces instead of the service?
|
|
|
|
Service *Service
|
|
|
|
|
2020-07-24 18:13:15 +01:00
|
|
|
Bucket metabase.BucketLocation
|
2020-07-24 19:57:11 +01:00
|
|
|
|
2020-07-24 18:13:15 +01:00
|
|
|
// TODO: use a Template pb.OrderLimit here?
|
2020-07-24 19:57:11 +01:00
|
|
|
RootPieceID storj.PieceID
|
|
|
|
|
|
|
|
PieceExpiration time.Time
|
|
|
|
OrderCreation time.Time
|
|
|
|
OrderExpiration time.Time
|
|
|
|
|
|
|
|
PublicKey storj.PiecePublicKey
|
|
|
|
PrivateKey storj.PiecePrivateKey
|
|
|
|
|
|
|
|
Serial storj.SerialNumber
|
|
|
|
Action pb.PieceAction
|
|
|
|
Limit int64
|
|
|
|
|
2020-07-24 18:13:15 +01:00
|
|
|
EncryptedMetadataKeyID []byte
|
|
|
|
EncryptedMetadata []byte
|
|
|
|
|
2020-07-24 19:57:11 +01:00
|
|
|
AddressedLimits []*pb.AddressedOrderLimit
|
|
|
|
}
|
|
|
|
|
|
|
|
// createSerial creates a timestamped serial number.
|
|
|
|
func createSerial(orderExpiration time.Time) (_ storj.SerialNumber, err error) {
|
|
|
|
var serial storj.SerialNumber
|
|
|
|
|
|
|
|
binary.BigEndian.PutUint64(serial[0:8], uint64(orderExpiration.Unix()))
|
|
|
|
_, err = rand.Read(serial[8:])
|
|
|
|
if err != nil {
|
|
|
|
return storj.SerialNumber{}, ErrSigner.Wrap(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return serial, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewSigner creates an order limit signer.
|
2020-07-24 18:13:15 +01:00
|
|
|
func NewSigner(service *Service, rootPieceID storj.PieceID, pieceExpiration time.Time, orderCreation time.Time, limit int64, action pb.PieceAction, bucket metabase.BucketLocation) (*Signer, error) {
|
2020-07-24 19:57:11 +01:00
|
|
|
signer := &Signer{}
|
|
|
|
signer.Service = service
|
|
|
|
|
2020-07-24 18:13:15 +01:00
|
|
|
signer.Bucket = bucket
|
|
|
|
|
2020-07-24 19:57:11 +01:00
|
|
|
signer.RootPieceID = rootPieceID
|
|
|
|
|
|
|
|
signer.PieceExpiration = pieceExpiration
|
|
|
|
signer.OrderCreation = orderCreation
|
2020-08-14 15:48:39 +01:00
|
|
|
signer.OrderExpiration = orderCreation.Add(service.orderExpiration)
|
2020-07-24 19:57:11 +01:00
|
|
|
|
|
|
|
var err error
|
|
|
|
signer.PublicKey, signer.PrivateKey, err = storj.NewPieceKey()
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrSigner.Wrap(err)
|
|
|
|
}
|
|
|
|
|
2020-08-14 15:48:39 +01:00
|
|
|
signer.Serial, err = createSerial(signer.OrderExpiration)
|
2020-07-24 19:57:11 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, ErrSigner.Wrap(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
signer.Action = action
|
|
|
|
signer.Limit = limit
|
|
|
|
|
|
|
|
return signer, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewSignerGet creates a new signer for get orders.
|
2020-07-24 18:13:15 +01:00
|
|
|
func NewSignerGet(service *Service, rootPieceID storj.PieceID, orderCreation time.Time, limit int64, bucket metabase.BucketLocation) (*Signer, error) {
|
|
|
|
return NewSigner(service, rootPieceID, time.Time{}, orderCreation, limit, pb.PieceAction_GET, bucket)
|
2020-07-24 19:57:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewSignerPut creates a new signer for put orders.
|
2020-07-24 18:13:15 +01:00
|
|
|
func NewSignerPut(service *Service, pieceExpiration time.Time, orderCreation time.Time, limit int64, bucket metabase.BucketLocation) (*Signer, error) {
|
2020-07-24 19:57:11 +01:00
|
|
|
rootPieceID := storj.NewPieceID()
|
2020-07-24 18:13:15 +01:00
|
|
|
return NewSigner(service, rootPieceID, pieceExpiration, orderCreation, limit, pb.PieceAction_PUT, bucket)
|
2020-07-24 19:57:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewSignerDelete creates a new signer for delete orders.
|
2020-07-24 18:13:15 +01:00
|
|
|
func NewSignerDelete(service *Service, rootPieceID storj.PieceID, orderCreation time.Time, bucket metabase.BucketLocation) (*Signer, error) {
|
|
|
|
return NewSigner(service, rootPieceID, time.Time{}, orderCreation, 0, pb.PieceAction_DELETE, bucket)
|
2020-07-24 19:57:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewSignerRepairGet creates a new signer for get repair orders.
|
2020-07-24 18:13:15 +01:00
|
|
|
func NewSignerRepairGet(service *Service, rootPieceID storj.PieceID, orderCreation time.Time, pieceSize int64, bucket metabase.BucketLocation) (*Signer, error) {
|
|
|
|
return NewSigner(service, rootPieceID, time.Time{}, orderCreation, pieceSize, pb.PieceAction_GET_REPAIR, bucket)
|
2020-07-24 19:57:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewSignerRepairPut creates a new signer for put repair orders.
|
2020-07-24 18:13:15 +01:00
|
|
|
func NewSignerRepairPut(service *Service, rootPieceID storj.PieceID, pieceExpiration time.Time, orderCreation time.Time, pieceSize int64, bucket metabase.BucketLocation) (*Signer, error) {
|
|
|
|
return NewSigner(service, rootPieceID, pieceExpiration, orderCreation, pieceSize, pb.PieceAction_PUT_REPAIR, bucket)
|
2020-07-24 19:57:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewSignerAudit creates a new signer for audit orders.
|
2020-07-24 18:13:15 +01:00
|
|
|
func NewSignerAudit(service *Service, rootPieceID storj.PieceID, orderCreation time.Time, pieceSize int64, bucket metabase.BucketLocation) (*Signer, error) {
|
|
|
|
return NewSigner(service, rootPieceID, time.Time{}, orderCreation, pieceSize, pb.PieceAction_GET_AUDIT, bucket)
|
2020-07-24 19:57:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewSignerGracefulExit creates a new signer for graceful exit orders.
|
2020-07-24 18:13:15 +01:00
|
|
|
func NewSignerGracefulExit(service *Service, rootPieceID storj.PieceID, orderCreation time.Time, shareSize int32, bucket metabase.BucketLocation) (*Signer, error) {
|
2020-07-24 19:57:11 +01:00
|
|
|
// TODO: we're using zero time.Time for piece expiration for some reason.
|
|
|
|
|
2020-08-14 15:36:30 +01:00
|
|
|
// TODO: we're using `PUT_REPAIR` here even though we should be using `PUT`, such
|
|
|
|
// that the storage node cannot distinguish between requests. We can't use `PUT`
|
2020-07-24 19:57:11 +01:00
|
|
|
// because we don't want to charge bucket owners for graceful exit bandwidth, and
|
|
|
|
// we can't use `PUT_GRACEFUL_EXIT` because storagenode will only accept upload
|
|
|
|
// orders with `PUT` or `PUT_REPAIR` as the action. we also don't have a bunch of
|
|
|
|
// supporting code/tables to aggregate `PUT_GRACEFUL_EXIT` bandwidth into our rollups
|
|
|
|
// and stuff. so, for now, we just use `PUT_REPAIR` because it's the least bad of
|
|
|
|
// our options. this should be fixed.
|
2020-07-24 18:13:15 +01:00
|
|
|
return NewSigner(service, rootPieceID, time.Time{}, orderCreation, int64(shareSize), pb.PieceAction_PUT_REPAIR, bucket)
|
2020-07-24 19:57:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sign signs an order limit for the specified node.
|
|
|
|
func (signer *Signer) Sign(ctx context.Context, node storj.NodeURL, pieceNum int32) (_ *pb.AddressedOrderLimit, err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
2020-07-24 18:13:15 +01:00
|
|
|
if signer.Service.includeEncryptedMetadata && len(signer.EncryptedMetadata) == 0 {
|
|
|
|
encryptionKey := signer.Service.encryptionKeys.Default
|
|
|
|
if encryptionKey.IsZero() {
|
|
|
|
return nil, ErrSigner.New("default encryption key is missing")
|
|
|
|
}
|
|
|
|
|
|
|
|
bucketID, err := signer.Service.buckets.GetBucketID(ctx, signer.Bucket)
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrSigner.Wrap(err)
|
|
|
|
}
|
|
|
|
|
2020-11-20 19:16:31 +00:00
|
|
|
encrypted, err := encryptionKey.EncryptMetadata(
|
|
|
|
signer.Serial,
|
|
|
|
&pb.OrderLimitMetadata{
|
|
|
|
BucketId: bucketID[:],
|
|
|
|
},
|
|
|
|
)
|
2020-07-24 18:13:15 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, ErrSigner.Wrap(err)
|
|
|
|
}
|
|
|
|
signer.EncryptedMetadataKeyID = encryptionKey.ID[:]
|
2020-11-20 19:16:31 +00:00
|
|
|
signer.EncryptedMetadata = encrypted
|
2020-07-24 18:13:15 +01:00
|
|
|
}
|
|
|
|
|
2020-07-24 19:57:11 +01:00
|
|
|
limit := &pb.OrderLimit{
|
|
|
|
SerialNumber: signer.Serial,
|
|
|
|
SatelliteId: signer.Service.satellite.ID(),
|
|
|
|
UplinkPublicKey: signer.PublicKey,
|
|
|
|
StorageNodeId: node.ID,
|
|
|
|
|
|
|
|
PieceId: signer.RootPieceID.Derive(node.ID, pieceNum),
|
|
|
|
Limit: signer.Limit,
|
|
|
|
Action: signer.Action,
|
|
|
|
|
|
|
|
PieceExpiration: signer.PieceExpiration,
|
|
|
|
OrderCreation: signer.OrderCreation,
|
|
|
|
OrderExpiration: signer.OrderExpiration,
|
|
|
|
|
|
|
|
SatelliteAddress: signer.Service.satelliteAddress,
|
2020-07-24 18:13:15 +01:00
|
|
|
|
|
|
|
EncryptedMetadataKeyId: signer.EncryptedMetadataKeyID,
|
|
|
|
EncryptedMetadata: signer.EncryptedMetadata,
|
2020-07-24 19:57:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
signedLimit, err := signing.SignOrderLimit(ctx, signer.Service.satellite, limit)
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrSigner.Wrap(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
addressedLimit := &pb.AddressedOrderLimit{
|
|
|
|
Limit: signedLimit,
|
|
|
|
StorageNodeAddress: &pb.NodeAddress{
|
|
|
|
Address: node.Address,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
signer.AddressedLimits = append(signer.AddressedLimits, addressedLimit)
|
|
|
|
|
|
|
|
return addressedLimit, nil
|
|
|
|
}
|