[#1933] cli: Support binary sessions

There is a need to support NeoFS-binary sessions along with JSON ones in
NeoFS CLI.

Provide generic `common.ReadBinaryOrJSON` functions which tries to
decode NeoFS-binary structure and falls back to JSON format. Use this
function in all places with token reading.

Signed-off-by: Leonard Lyubich <ctulhurider@gmail.com>
This commit is contained in:
Leonard Lyubich 2022-10-20 13:40:33 +04:00 committed by fyrchik
parent 04b67f3ba5
commit 8bba490c30
24 changed files with 259 additions and 206 deletions

View file

@ -21,6 +21,7 @@ Changelog for NeoFS Node
- Setting node's network state to `MAINTENANCE` while network settings forbid it (#1916)
- Do not panic during API client creation (#1936)
- Correctly sign new epoch transaction in neofs-adm for a committee of more than 4 nodes (#1949)
- Inability to provide session to NeoFS CLI in a NeoFS-binary format (#1933)
### Removed
### Updated

View file

@ -2,6 +2,7 @@ package common
import (
"encoding/json"
"errors"
"fmt"
"os"
@ -18,39 +19,47 @@ func ReadBearerToken(cmd *cobra.Command, flagname string) *bearer.Token {
return nil
}
data, err := os.ReadFile(path)
ExitOnErr(cmd, "can't read bearer token file: %w", err)
PrintVerbose("Reading bearer token from file [%s]...", path)
var tok bearer.Token
if err := tok.UnmarshalJSON(data); err != nil {
err = tok.Unmarshal(data)
ExitOnErr(cmd, "can't decode bearer token: %w", err)
PrintVerbose("Using binary encoded bearer token")
} else {
PrintVerbose("Using JSON encoded bearer token")
}
err = ReadBinaryOrJSON(&tok, path)
ExitOnErr(cmd, "invalid bearer token: %v", err)
return &tok
}
// ReadSessionToken calls ReadSessionTokenErr and exists on error.
func ReadSessionToken(cmd *cobra.Command, dst json.Unmarshaler, fPath string) {
ExitOnErr(cmd, "", ReadSessionTokenErr(dst, fPath))
// BinaryOrJSON is an interface of entities which provide json.Unmarshaler
// and NeoFS binary decoder.
type BinaryOrJSON interface {
Unmarshal([]byte) error
json.Unmarshaler
}
// ReadSessionTokenErr reads session token as JSON file with session token
// from path provided in a specified flag.
func ReadSessionTokenErr(dst json.Unmarshaler, fPath string) error {
// ReadBinaryOrJSON reads file data using provided path and decodes
// BinaryOrJSON from the data.
func ReadBinaryOrJSON(dst BinaryOrJSON, fPath string) error {
PrintVerbose("Reading file [%s]...", fPath)
// try to read session token from file
data, err := os.ReadFile(fPath)
if err != nil {
return fmt.Errorf("could not open file with session token <%s>: %w", fPath, err)
return fmt.Errorf("read file <%s>: %w", fPath, err)
}
err = dst.UnmarshalJSON(data)
PrintVerbose("Trying to decode binary...")
err = dst.Unmarshal(data)
if err != nil {
return fmt.Errorf("could not unmarshal session token from file: %w", err)
PrintVerbose("Failed to decode binary: %v", err)
PrintVerbose("Trying to decode JSON...")
err = dst.UnmarshalJSON(data)
if err != nil {
PrintVerbose("Failed to decode JSON: %v", err)
return errors.New("invalid format")
}
}
return nil

View file

@ -1,14 +1,19 @@
package commonflags
import "github.com/spf13/cobra"
import (
"fmt"
"github.com/spf13/cobra"
)
const SessionToken = "session"
// InitSession initializes session parameter for cmd.
func InitSession(cmd *cobra.Command) {
// InitSession registers SessionToken flag representing filepath to the token
// of the session with the given name. Supports NeoFS-binary and JSON files.
func InitSession(cmd *cobra.Command, name string) {
cmd.Flags().String(
SessionToken,
"",
"Path to a JSON-encoded container session token",
fmt.Sprintf("Filepath to a JSON- or binary-encoded token of the %s session", name),
)
}

View file

@ -14,7 +14,6 @@ import (
"github.com/nspcc-dev/neofs-sdk-go/container"
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/nspcc-dev/neofs-sdk-go/session"
subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
"github.com/nspcc-dev/neofs-sdk-go/user"
"github.com/spf13/cobra"
@ -74,13 +73,9 @@ It will be stored in sidechain when inner ring will accepts it.`,
var basicACL acl.Basic
common.ExitOnErr(cmd, "decode basic ACL string: %w", basicACL.DecodeString(containerACL))
var tok *session.Container
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken)
if sessionTokenPath != "" {
tok = new(session.Container)
common.ReadSessionToken(cmd, tok, sessionTokenPath)
tok := getSession(cmd)
if tok != nil {
issuer := tok.Issuer()
cnr.SetOwner(issuer)
} else {

View file

@ -9,7 +9,6 @@ import (
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/spf13/cobra"
)
@ -21,13 +20,7 @@ Only owner of the container has a permission to remove container.`,
Run: func(cmd *cobra.Command, args []string) {
id := parseContainerID(cmd)
var tok *session.Container
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken)
if sessionTokenPath != "" {
tok = new(session.Container)
common.ReadSessionToken(cmd, tok, sessionTokenPath)
}
tok := getSession(cmd)
pk := key.Get(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)

View file

@ -9,7 +9,6 @@ import (
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
"github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/spf13/cobra"
@ -35,16 +34,17 @@ var listContainerObjectsCmd = &cobra.Command{
filters := new(object.SearchFilters)
filters.AddRootFilter() // search only user created objects
pk := key.GetOrGenerate(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, key.GetOrGenerate(cmd), commonflags.RPC)
var prmSearch internalclient.SearchObjectsPrm
var prmHead internalclient.HeadObjectPrm
prmSearch.SetClient(cli)
if flagVarListObjectsPrintAttr {
sessionCli.Prepare(cmd, id, nil, pk, &prmSearch, &prmHead)
prmHead.SetClient(cli)
objectCli.Prepare(cmd, &prmSearch, &prmHead)
} else {
sessionCli.Prepare(cmd, id, nil, pk, &prmSearch)
objectCli.Prepare(cmd, &prmSearch)
}

View file

@ -45,11 +45,14 @@ func init() {
commonflags.InitAPI(containerCommand)
}
for _, cmd := range []*cobra.Command{
createContainerCmd,
deleteContainerCmd,
setExtendedACLCmd,
for _, el := range []struct {
cmd *cobra.Command
verb string
}{
{createContainerCmd, "PUT"},
{deleteContainerCmd, "DELETE"},
{setExtendedACLCmd, "SETEACL"},
} {
commonflags.InitSession(cmd)
commonflags.InitSession(el.cmd, "container "+el.verb)
}
}

View file

@ -9,7 +9,6 @@ import (
"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-node/cmd/neofs-cli/internal/key"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/spf13/cobra"
)
@ -28,13 +27,7 @@ Container ID in EACL table will be substituted with ID from the CLI.`,
id := parseContainerID(cmd)
eaclTable := common.ReadEACL(cmd, flagVarsSetEACL.srcPath)
var tok *session.Container
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken)
if sessionTokenPath != "" {
tok = new(session.Container)
common.ReadSessionToken(cmd, tok, sessionTokenPath)
}
tok := getSession(cmd)
eaclTable.SetCID(id)

View file

@ -4,7 +4,9 @@ import (
"errors"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/spf13/cobra"
)
@ -30,3 +32,26 @@ func parseContainerID(cmd *cobra.Command) cid.ID {
common.ExitOnErr(cmd, "can't decode container ID value: %w", err)
return id
}
// decodes session.Container from the file by path provided in
// commonflags.SessionToken flag. Returns nil if the path is not specified.
func getSession(cmd *cobra.Command) *session.Container {
common.PrintVerbose("Reading container session...")
path, _ := cmd.Flags().GetString(commonflags.SessionToken)
if path == "" {
common.PrintVerbose("Session not provided.")
return nil
}
common.PrintVerbose("Reading container session from the file [%s]...", path)
var res session.Container
err := common.ReadBinaryOrJSON(&res, path)
common.ExitOnErr(cmd, "read container session: %v", err)
common.PrintVerbose("Session successfully read.")
return &res
}

View file

@ -5,7 +5,6 @@ import (
"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-node/cmd/neofs-cli/internal/key"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/spf13/cobra"
@ -21,7 +20,7 @@ var objectDelCmd = &cobra.Command{
func initObjectDeleteCmd() {
commonflags.Init(objectDelCmd)
commonflags.InitSession(objectDelCmd)
initFlagSession(objectDelCmd, "DELETE")
flags := objectDelCmd.Flags()
@ -40,7 +39,7 @@ func deleteObject(cmd *cobra.Command, _ []string) {
pk := key.GetOrGenerate(cmd)
var prm internalclient.DeleteObjectPrm
sessionCli.Prepare(cmd, cnr, &obj, pk, &prm)
ReadOrOpenSession(cmd, &prm, pk, cnr, &obj)
Prepare(cmd, &prm)
prm.SetAddress(objAddr)

View file

@ -25,7 +25,7 @@ var objectGetCmd = &cobra.Command{
func initObjectGetCmd() {
commonflags.Init(objectGetCmd)
commonflags.InitSession(objectGetCmd)
initFlagSession(objectGetCmd, "GET")
flags := objectGetCmd.Flags()

View file

@ -9,7 +9,6 @@ import (
"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-node/cmd/neofs-cli/internal/key"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
"github.com/nspcc-dev/neofs-sdk-go/checksum"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
@ -69,7 +68,6 @@ func getObjectHash(cmd *cobra.Command, _ []string) {
fullHash := len(ranges) == 0
if fullHash {
var headPrm internalclient.HeadObjectPrm
sessionCli.Prepare(cmd, cnr, &obj, pk, &headPrm)
Prepare(cmd, &headPrm)
headPrm.SetAddress(objAddr)

View file

@ -27,7 +27,7 @@ var objectHeadCmd = &cobra.Command{
func initObjectHeadCmd() {
commonflags.Init(objectHeadCmd)
commonflags.InitSession(objectHeadCmd)
initFlagSession(objectHeadCmd, "HEAD")
flags := objectHeadCmd.Flags()

View file

@ -12,7 +12,6 @@ import (
"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-node/cmd/neofs-cli/internal/key"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
@ -79,8 +78,7 @@ var objectLockCmd = &cobra.Command{
obj.SetPayload(lock.Marshal())
var prm internalclient.PutObjectPrm
sessionCli.Prepare(cmd, cnr, nil, key, &prm)
ReadOrOpenSession(cmd, &prm, key, cnr, nil)
Prepare(cmd, &prm)
prm.SetHeader(obj)
@ -94,7 +92,7 @@ var objectLockCmd = &cobra.Command{
func initCommandObjectLock() {
commonflags.Init(objectLockCmd)
commonflags.InitSession(objectLockCmd)
initFlagSession(objectLockCmd, "PUT")
objectLockCmd.Flags().Uint64P(commonflags.ExpireAt, "e", 0, "Lock expiration epoch")
objectLockCmd.Flags().Uint64(commonflags.Lifetime, 0, "Lock lifetime")

View file

@ -14,7 +14,6 @@ import (
"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-node/cmd/neofs-cli/internal/key"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/object"
"github.com/nspcc-dev/neofs-sdk-go/user"
@ -37,7 +36,7 @@ var objectPutCmd = &cobra.Command{
func initObjectPutCmd() {
commonflags.Init(objectPutCmd)
commonflags.InitSession(objectPutCmd)
initFlagSession(objectPutCmd, "PUT")
flags := objectPutCmd.Flags()
@ -109,7 +108,7 @@ func putObject(cmd *cobra.Command, _ []string) {
}
var prm internalclient.PutObjectPrm
sessionCli.Prepare(cmd, cnr, nil, pk, &prm)
ReadOrOpenSession(cmd, &prm, pk, cnr, nil)
Prepare(cmd, &prm)
prm.SetHeader(obj)

View file

@ -28,7 +28,7 @@ var objectRangeCmd = &cobra.Command{
func initObjectRangeCmd() {
commonflags.Init(objectRangeCmd)
commonflags.InitSession(objectRangeCmd)
initFlagSession(objectRangeCmd, "RANGE")
flags := objectRangeCmd.Flags()

View file

@ -30,7 +30,7 @@ var (
func initObjectSearchCmd() {
commonflags.Init(objectSearchCmd)
commonflags.InitSession(objectSearchCmd)
initFlagSession(objectSearchCmd, "SEARCH")
flags := objectSearchCmd.Flags()

View file

@ -9,7 +9,9 @@ import (
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"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
"github.com/nspcc-dev/neofs-sdk-go/bearer"
"github.com/nspcc-dev/neofs-sdk-go/client"
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"
@ -87,50 +89,67 @@ func readOID(cmd *cobra.Command, id *oid.ID) {
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 {
// SessionPrm is a common interface of object operation's input which supports
// sessions.
type SessionPrm interface {
SetSessionToken(*session.Object)
SetClient(*client.Client)
}
// 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 _readVerifiedSession and object as nil.
func readSessionGlobal(cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID) {
_readVerifiedSession(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)
// forwards all parameters to _readVerifiedSession.
func readSession(cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj oid.ID) {
_readVerifiedSession(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:
// decodes session.Object from the file by path specified in the
// commonflags.SessionToken flag. Returns nil if flag is not set.
func getSession(cmd *cobra.Command) *session.Object {
common.PrintVerbose("Trying to read session from the file...")
path, _ := cmd.Flags().GetString(commonflags.SessionToken)
if path == "" {
common.PrintVerbose("File with session token is not provided.")
return nil
}
common.PrintVerbose("Reading session from the file [%s]...", path)
var tok session.Object
err := common.ReadBinaryOrJSON(&tok, path)
common.ExitOnErr(cmd, "read session: %v", err)
return &tok
}
// decodes object session from JSON file from commonflags.SessionToken command
// flag if it is provided, and writes resulting session into the provided SessionPrm.
// Returns flag presence. Checks:
//
// - if session verb corresponds to given sessionPrm according to its type
// - 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:
// 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) {
func _readVerifiedSession(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:
@ -143,32 +162,125 @@ func _readSession(cmd *cobra.Command, dst sessionPrm, key *ecdsa.PrivateKey, cnr
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.")
tok := getSession(cmd)
if tok == nil {
return
}
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)
}
// ReadOrOpenSession opens client connection and calls ReadOrOpenSessionViaClient with it.
func ReadOrOpenSession(cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) {
cli := internal.GetSDKClientByFlag(cmd, key, commonflags.RPC)
ReadOrOpenSessionViaClient(cmd, dst, cli, key, cnr, obj)
}
// ReadOrOpenSessionViaClient tries to read session from the file specified in
// commonflags.SessionToken flag, finalizes structures of the decoded token
// and write the result into provided SessionPrm. If file is missing,
// ReadOrOpenSessionViaClient calls OpenSessionViaClient.
func ReadOrOpenSessionViaClient(cmd *cobra.Command, dst SessionPrm, cli *client.Client, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) {
tok := getSession(cmd)
if tok == nil {
OpenSessionViaClient(cmd, dst, cli, key, cnr, obj)
return
}
finalizeSession(cmd, dst, tok, key, cnr, obj)
dst.SetClient(cli)
}
// OpenSession opens client connection and calls OpenSessionViaClient with it.
func OpenSession(cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) {
cli := internal.GetSDKClientByFlag(cmd, key, commonflags.RPC)
OpenSessionViaClient(cmd, dst, cli, key, cnr, obj)
}
// OpenSessionViaClient opens object session with the remote node, finalizes
// structure of the session token and writes the result into the provided
// SessionPrm. Also writes provided client connection to the SessionPrm.
//
// SessionPrm MUST be one of:
//
// *internal.PutObjectPrm
// *internal.DeleteObjectPrm
func OpenSessionViaClient(cmd *cobra.Command, dst SessionPrm, cli *client.Client, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) {
var tok session.Object
const sessionLifetime = 10 // in NeoFS epochs
common.PrintVerbose("Opening remote session with the node...")
err := sessionCli.CreateSession(&tok, cli, sessionLifetime)
common.ExitOnErr(cmd, "open remote session: %w", err)
common.PrintVerbose("Session successfully opened.")
finalizeSession(cmd, dst, &tok, key, cnr, obj)
dst.SetClient(cli)
}
// specifies session verb, binds the session to the given container and limits
// the session by the given object (if specified). After all data is written,
// signs session using provided private key and writes the session into the
// given SessionPrm.
//
// SessionPrm MUST be one of:
//
// *internal.PutObjectPrm
// *internal.DeleteObjectPrm
func finalizeSession(cmd *cobra.Command, dst SessionPrm, tok *session.Object, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) {
common.PrintVerbose("Finalizing session token...")
switch dst.(type) {
default:
panic(fmt.Sprintf("unsupported op parameters %T", dst))
case *internal.PutObjectPrm:
common.PrintVerbose("Binding session to object PUT...")
tok.ForVerb(session.VerbObjectPut)
case *internal.DeleteObjectPrm:
common.PrintVerbose("Binding session to object DELETE...")
tok.ForVerb(session.VerbObjectDelete)
}
common.PrintVerbose("Binding session to container %s...", cnr)
tok.BindContainer(cnr)
if obj != nil {
common.PrintVerbose("Limiting session by object %s...", obj)
tok.LimitByObjects(*obj)
}
common.PrintVerbose("Signing session...")
err := tok.Sign(*key)
common.ExitOnErr(cmd, "sign session: %w", err)
common.PrintVerbose("Session token successfully formed and attached to the request.")
dst.SetSessionToken(tok)
}
// calls commonflags.InitSession with "object <verb>" name.
func initFlagSession(cmd *cobra.Command, verb string) {
commonflags.InitSession(cmd, "object "+verb)
}

View file

@ -1,75 +0,0 @@
package session
import (
"crypto/ecdsa"
"os"
internalclient "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/client"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/spf13/cobra"
)
// RPCParameters represents parameters for operations with session token.
type RPCParameters interface {
SetClient(*client.Client)
SetSessionToken(*session.Object)
}
const sessionTokenLifetime = 10 // in epochs
// Prepare prepares session for a command.
func Prepare(cmd *cobra.Command, cnr cid.ID, obj *oid.ID, key *ecdsa.PrivateKey, prms ...RPCParameters) {
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
var tok session.Object
if tokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken); len(tokenPath) != 0 {
data, err := os.ReadFile(tokenPath)
common.ExitOnErr(cmd, "can't read session token: %w", err)
if err := tok.Unmarshal(data); err != nil {
err = tok.UnmarshalJSON(data)
common.ExitOnErr(cmd, "can't unmarshal session token: %w", err)
}
} else {
err := CreateSession(&tok, cli, sessionTokenLifetime)
common.ExitOnErr(cmd, "create session: %w", err)
}
for i := range prms {
tok := tok
switch prms[i].(type) {
case *internalclient.GetObjectPrm:
tok.ForVerb(session.VerbObjectGet)
case *internalclient.HeadObjectPrm:
tok.ForVerb(session.VerbObjectHead)
case *internalclient.PutObjectPrm:
tok.ForVerb(session.VerbObjectPut)
case *internalclient.DeleteObjectPrm:
tok.ForVerb(session.VerbObjectDelete)
case *internalclient.SearchObjectsPrm:
tok.ForVerb(session.VerbObjectSearch)
case *internalclient.PayloadRangePrm:
tok.ForVerb(session.VerbObjectRange)
case *internalclient.HashPayloadRangesPrm:
tok.ForVerb(session.VerbObjectRangeHash)
default:
panic("invalid client parameter type")
}
tok.BindContainer(cnr)
if obj != nil {
tok.LimitByObjects(*obj)
}
err := tok.Sign(*key)
common.ExitOnErr(cmd, "session token signing: %w", err)
prms[i].SetClient(cli)
prms[i].SetSessionToken(&tok)
}
}

View file

@ -6,7 +6,6 @@ import (
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/spf13/cobra"
@ -40,7 +39,7 @@ func delSG(cmd *cobra.Command, _ []string) {
addr := readObjectAddress(cmd, &cnr, &obj)
var prm internalclient.DeleteObjectPrm
sessionCli.Prepare(cmd, cnr, &obj, pk, &prm)
objectCli.OpenSession(cmd, &prm, pk, cnr, &obj)
objectCli.Prepare(cmd, &prm)
prm.SetAddress(addr)

View file

@ -8,7 +8,6 @@ import (
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
storagegroupSDK "github.com/nspcc-dev/neofs-sdk-go/storagegroup"
@ -46,9 +45,11 @@ func getSG(cmd *cobra.Command, _ []string) {
pk := key.GetOrGenerate(cmd)
buf := bytes.NewBuffer(nil)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)
var prm internalclient.GetObjectPrm
sessionCli.Prepare(cmd, cnr, &obj, pk, &prm)
objectCli.Prepare(cmd, &prm)
prm.SetClient(cli)
raw, _ := cmd.Flags().GetBool(sgRawFlag)
prm.SetRawFlag(raw)

View file

@ -6,7 +6,6 @@ import (
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/storagegroup"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/spf13/cobra"
@ -32,9 +31,11 @@ func listSG(cmd *cobra.Command, _ []string) {
pk := key.GetOrGenerate(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)
var prm internalclient.SearchObjectsPrm
sessionCli.Prepare(cmd, cnr, nil, pk, &prm)
objectCli.Prepare(cmd, &prm)
prm.SetClient(cli)
prm.SetContainerID(cnr)
prm.SetFilters(storagegroup.SearchQuery())

View file

@ -10,7 +10,6 @@ import (
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object"
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/storagegroup"
"github.com/nspcc-dev/neofs-sdk-go/container"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
@ -83,10 +82,11 @@ func putSG(cmd *cobra.Command, _ []string) {
resGetCnr, err := internalclient.GetContainer(getCnrPrm)
common.ExitOnErr(cmd, "get container RPC call: %w", err)
sessionCli.Prepare(cmd, cnr, nil, pk, &putPrm)
objectCli.OpenSessionViaClient(cmd, &putPrm, cli, pk, cnr, nil)
objectCli.Prepare(cmd, &headPrm, &putPrm)
headPrm.SetRawFlag(true)
headPrm.SetClient(cli)
sg, err := storagegroup.CollectMembers(sgHeadReceiver{
cmd: cmd,
@ -128,9 +128,6 @@ type sgHeadReceiver struct {
}
func (c sgHeadReceiver) Head(addr oid.Address) (interface{}, error) {
obj := addr.Object()
sessionCli.Prepare(c.cmd, addr.Container(), &obj, c.key, &c.prm)
c.prm.SetAddress(addr)
res, err := internalclient.HeadObject(c.prm)

View file

@ -42,7 +42,7 @@ func signSessionToken(cmd *cobra.Command, _ []string) {
type iTokenSession interface {
json.Marshaler
json.Unmarshaler
common.BinaryOrJSON
Sign(ecdsa.PrivateKey) error
}
var errLast error
@ -52,14 +52,14 @@ func signSessionToken(cmd *cobra.Command, _ []string) {
new(session.Object),
new(session.Container),
} {
errLast = common.ReadSessionTokenErr(el, fPath)
errLast = common.ReadBinaryOrJSON(el, fPath)
if errLast == nil {
stok = el
break
}
}
common.ExitOnErr(cmd, "", errLast)
common.ExitOnErr(cmd, "decode session: %v", errLast)
pk := key.GetOrGenerate(cmd)