1cb892c579
Signed-off-by: Evgenii Stratonikov <evgeniy@morphbits.ru>
174 lines
5.2 KiB
Go
174 lines
5.2 KiB
Go
package object
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
internal "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
|
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
const (
|
|
bearerTokenFlag = "bearer"
|
|
|
|
rawFlag = "raw"
|
|
rawFlagDesc = "Set raw request option"
|
|
)
|
|
|
|
type RPCParameters interface {
|
|
SetBearerToken(prm *bearer.Token)
|
|
SetTTL(uint32)
|
|
SetXHeaders([]string)
|
|
}
|
|
|
|
// InitBearer adds bearer token flag to a command.
|
|
func InitBearer(cmd *cobra.Command) {
|
|
flags := cmd.Flags()
|
|
flags.String(bearerTokenFlag, "", "File with signed JSON or binary encoded bearer token")
|
|
}
|
|
|
|
// Prepare prepares object-related parameters for a command.
|
|
func Prepare(cmd *cobra.Command, prms ...RPCParameters) {
|
|
ttl := viper.GetUint32(commonflags.TTL)
|
|
common.PrintVerbose("TTL: %d", ttl)
|
|
|
|
for i := range prms {
|
|
btok := common.ReadBearerToken(cmd, bearerTokenFlag)
|
|
|
|
prms[i].SetBearerToken(btok)
|
|
prms[i].SetTTL(ttl)
|
|
prms[i].SetXHeaders(parseXHeaders(cmd))
|
|
}
|
|
}
|
|
|
|
func parseXHeaders(cmd *cobra.Command) []string {
|
|
xHeaders, _ := cmd.Flags().GetStringSlice(commonflags.XHeadersKey)
|
|
xs := make([]string, 0, 2*len(xHeaders))
|
|
|
|
for i := range xHeaders {
|
|
kv := strings.SplitN(xHeaders[i], "=", 2)
|
|
if len(kv) != 2 {
|
|
panic(fmt.Errorf("invalid X-Header format: %s", xHeaders[i]))
|
|
}
|
|
|
|
xs = append(xs, kv[0], kv[1])
|
|
}
|
|
|
|
return xs
|
|
}
|
|
|
|
func readObjectAddress(cmd *cobra.Command, cnr *cid.ID, obj *oid.ID) oid.Address {
|
|
readCID(cmd, cnr)
|
|
readOID(cmd, obj)
|
|
|
|
var addr oid.Address
|
|
addr.SetContainer(*cnr)
|
|
addr.SetObject(*obj)
|
|
return addr
|
|
}
|
|
|
|
func readCID(cmd *cobra.Command, id *cid.ID) {
|
|
err := id.DecodeString(cmd.Flag("cid").Value.String())
|
|
common.ExitOnErr(cmd, "decode container ID string: %w", err)
|
|
}
|
|
|
|
func readOID(cmd *cobra.Command, id *oid.ID) {
|
|
err := id.DecodeString(cmd.Flag("oid").Value.String())
|
|
common.ExitOnErr(cmd, "decode object ID string: %w", err)
|
|
}
|
|
|
|
// common interface of object operation's input which supports sessions.
|
|
// Implemented on types like internal.PutObjectPrm.
|
|
type sessionPrm interface {
|
|
SetSessionToken(*session.Object)
|
|
}
|
|
|
|
// forwards all parameters to _readSession and object as nil.
|
|
func readSessionGlobal(cmd *cobra.Command, dst sessionPrm, key *ecdsa.PrivateKey, cnr cid.ID) {
|
|
_readSession(cmd, dst, key, cnr, nil)
|
|
}
|
|
|
|
// forwards all parameters to _readSession.
|
|
func readSession(cmd *cobra.Command, dst sessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj oid.ID) {
|
|
_readSession(cmd, dst, key, cnr, &obj)
|
|
}
|
|
|
|
// decodes object session from JSON file from "session" command flag if it is provided,
|
|
// and writes resulting session into the provided sessionPrm. Checks:
|
|
//
|
|
// - if session verb corresponds to given sessionPrm according to its type
|
|
// - relation to the given container
|
|
// - relation to the given object if non-nil
|
|
// - relation to the given private key used within the command
|
|
// - session signature
|
|
//
|
|
// sessionPrm MUST be one of:
|
|
//
|
|
// *internal.PutObjectPrm
|
|
// *internal.DeleteObjectPrm
|
|
// *internal.GetObjectPrm
|
|
// *internal.HeadObjectPrm
|
|
// *internal.SearchObjectsPrm
|
|
// *internal.PayloadRangePrm
|
|
// *internal.HashPayloadRangesPrm
|
|
func _readSession(cmd *cobra.Command, dst sessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) {
|
|
var cmdVerb session.ObjectVerb
|
|
|
|
switch dst.(type) {
|
|
default:
|
|
panic(fmt.Sprintf("unsupported op parameters %T", dst))
|
|
case *internal.PutObjectPrm:
|
|
cmdVerb = session.VerbObjectPut
|
|
case *internal.DeleteObjectPrm:
|
|
cmdVerb = session.VerbObjectDelete
|
|
case *internal.GetObjectPrm:
|
|
cmdVerb = session.VerbObjectGet
|
|
case *internal.HeadObjectPrm:
|
|
cmdVerb = session.VerbObjectHead
|
|
case *internal.SearchObjectsPrm:
|
|
cmdVerb = session.VerbObjectSearch
|
|
case *internal.PayloadRangePrm:
|
|
cmdVerb = session.VerbObjectRange
|
|
case *internal.HashPayloadRangesPrm:
|
|
cmdVerb = session.VerbObjectRangeHash
|
|
}
|
|
|
|
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken)
|
|
if sessionTokenPath != "" {
|
|
common.PrintVerbose("Reading object session from the JSON file [%s]...", sessionTokenPath)
|
|
|
|
var tok session.Object
|
|
common.ReadSessionToken(cmd, &tok, sessionTokenPath)
|
|
|
|
common.PrintVerbose("Checking session correctness...")
|
|
|
|
switch false {
|
|
case tok.AssertContainer(cnr):
|
|
common.ExitOnErr(cmd, "", errors.New("unrelated container in the session"))
|
|
case obj == nil || tok.AssertObject(*obj):
|
|
common.ExitOnErr(cmd, "", errors.New("unrelated object in the session"))
|
|
case tok.AssertVerb(cmdVerb):
|
|
common.ExitOnErr(cmd, "", errors.New("wrong verb of the session"))
|
|
case tok.AssertAuthKey((*neofsecdsa.PublicKey)(&key.PublicKey)):
|
|
common.ExitOnErr(cmd, "", errors.New("unrelated key in the session"))
|
|
case tok.VerifySignature():
|
|
common.ExitOnErr(cmd, "", errors.New("invalid signature of the session data"))
|
|
}
|
|
|
|
common.PrintVerbose("Session is correct.")
|
|
|
|
dst.SetSessionToken(&tok)
|
|
} else {
|
|
common.PrintVerbose("Session is not provided.")
|
|
}
|
|
}
|