[#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) - Setting node's network state to `MAINTENANCE` while network settings forbid it (#1916)
- Do not panic during API client creation (#1936) - 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) - 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 ### Removed
### Updated ### Updated

View file

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

View file

@ -1,14 +1,19 @@
package commonflags package commonflags
import "github.com/spf13/cobra" import (
"fmt"
"github.com/spf13/cobra"
)
const SessionToken = "session" const SessionToken = "session"
// InitSession initializes session parameter for cmd. // InitSession registers SessionToken flag representing filepath to the token
func InitSession(cmd *cobra.Command) { // of the session with the given name. Supports NeoFS-binary and JSON files.
func InitSession(cmd *cobra.Command, name string) {
cmd.Flags().String( cmd.Flags().String(
SessionToken, 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"
"github.com/nspcc-dev/neofs-sdk-go/container/acl" "github.com/nspcc-dev/neofs-sdk-go/container/acl"
"github.com/nspcc-dev/neofs-sdk-go/netmap" "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" subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
"github.com/nspcc-dev/neofs-sdk-go/user" "github.com/nspcc-dev/neofs-sdk-go/user"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -74,13 +73,9 @@ It will be stored in sidechain when inner ring will accepts it.`,
var basicACL acl.Basic var basicACL acl.Basic
common.ExitOnErr(cmd, "decode basic ACL string: %w", basicACL.DecodeString(containerACL)) common.ExitOnErr(cmd, "decode basic ACL string: %w", basicACL.DecodeString(containerACL))
var tok *session.Container tok := getSession(cmd)
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken)
if sessionTokenPath != "" {
tok = new(session.Container)
common.ReadSessionToken(cmd, tok, sessionTokenPath)
if tok != nil {
issuer := tok.Issuer() issuer := tok.Issuer()
cnr.SetOwner(issuer) cnr.SetOwner(issuer)
} else { } 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/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object" objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/spf13/cobra" "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) { Run: func(cmd *cobra.Command, args []string) {
id := parseContainerID(cmd) id := parseContainerID(cmd)
var tok *session.Container tok := getSession(cmd)
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken)
if sessionTokenPath != "" {
tok = new(session.Container)
common.ReadSessionToken(cmd, tok, sessionTokenPath)
}
pk := key.Get(cmd) pk := key.Get(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) 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/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object" 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" "github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id" oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -35,16 +34,17 @@ var listContainerObjectsCmd = &cobra.Command{
filters := new(object.SearchFilters) filters := new(object.SearchFilters)
filters.AddRootFilter() // search only user created objects 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 prmSearch internalclient.SearchObjectsPrm
var prmHead internalclient.HeadObjectPrm var prmHead internalclient.HeadObjectPrm
prmSearch.SetClient(cli)
if flagVarListObjectsPrintAttr { if flagVarListObjectsPrintAttr {
sessionCli.Prepare(cmd, id, nil, pk, &prmSearch, &prmHead) prmHead.SetClient(cli)
objectCli.Prepare(cmd, &prmSearch, &prmHead) objectCli.Prepare(cmd, &prmSearch, &prmHead)
} else { } else {
sessionCli.Prepare(cmd, id, nil, pk, &prmSearch)
objectCli.Prepare(cmd, &prmSearch) objectCli.Prepare(cmd, &prmSearch)
} }

View file

@ -45,11 +45,14 @@ func init() {
commonflags.InitAPI(containerCommand) commonflags.InitAPI(containerCommand)
} }
for _, cmd := range []*cobra.Command{ for _, el := range []struct {
createContainerCmd, cmd *cobra.Command
deleteContainerCmd, verb string
setExtendedACLCmd, }{
{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/common"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "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-node/cmd/neofs-cli/internal/key"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -28,13 +27,7 @@ Container ID in EACL table will be substituted with ID from the CLI.`,
id := parseContainerID(cmd) id := parseContainerID(cmd)
eaclTable := common.ReadEACL(cmd, flagVarsSetEACL.srcPath) eaclTable := common.ReadEACL(cmd, flagVarsSetEACL.srcPath)
var tok *session.Container tok := getSession(cmd)
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken)
if sessionTokenPath != "" {
tok = new(session.Container)
common.ReadSessionToken(cmd, tok, sessionTokenPath)
}
eaclTable.SetCID(id) eaclTable.SetCID(id)

View file

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

View file

@ -25,7 +25,7 @@ var objectGetCmd = &cobra.Command{
func initObjectGetCmd() { func initObjectGetCmd() {
commonflags.Init(objectGetCmd) commonflags.Init(objectGetCmd)
commonflags.InitSession(objectGetCmd) initFlagSession(objectGetCmd, "GET")
flags := objectGetCmd.Flags() 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/common"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "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-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" "github.com/nspcc-dev/neofs-sdk-go/checksum"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id" cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/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 fullHash := len(ranges) == 0
if fullHash { if fullHash {
var headPrm internalclient.HeadObjectPrm var headPrm internalclient.HeadObjectPrm
sessionCli.Prepare(cmd, cnr, &obj, pk, &headPrm)
Prepare(cmd, &headPrm) Prepare(cmd, &headPrm)
headPrm.SetAddress(objAddr) headPrm.SetAddress(objAddr)

View file

@ -27,7 +27,7 @@ var objectHeadCmd = &cobra.Command{
func initObjectHeadCmd() { func initObjectHeadCmd() {
commonflags.Init(objectHeadCmd) commonflags.Init(objectHeadCmd)
commonflags.InitSession(objectHeadCmd) initFlagSession(objectHeadCmd, "HEAD")
flags := objectHeadCmd.Flags() 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/common"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "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-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" cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object" objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id" oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
@ -79,8 +78,7 @@ var objectLockCmd = &cobra.Command{
obj.SetPayload(lock.Marshal()) obj.SetPayload(lock.Marshal())
var prm internalclient.PutObjectPrm var prm internalclient.PutObjectPrm
ReadOrOpenSession(cmd, &prm, key, cnr, nil)
sessionCli.Prepare(cmd, cnr, nil, key, &prm)
Prepare(cmd, &prm) Prepare(cmd, &prm)
prm.SetHeader(obj) prm.SetHeader(obj)
@ -94,7 +92,7 @@ var objectLockCmd = &cobra.Command{
func initCommandObjectLock() { func initCommandObjectLock() {
commonflags.Init(objectLockCmd) commonflags.Init(objectLockCmd)
commonflags.InitSession(objectLockCmd) initFlagSession(objectLockCmd, "PUT")
objectLockCmd.Flags().Uint64P(commonflags.ExpireAt, "e", 0, "Lock expiration epoch") objectLockCmd.Flags().Uint64P(commonflags.ExpireAt, "e", 0, "Lock expiration epoch")
objectLockCmd.Flags().Uint64(commonflags.Lifetime, 0, "Lock lifetime") 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/common"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "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-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" 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/object"
"github.com/nspcc-dev/neofs-sdk-go/user" "github.com/nspcc-dev/neofs-sdk-go/user"
@ -37,7 +36,7 @@ var objectPutCmd = &cobra.Command{
func initObjectPutCmd() { func initObjectPutCmd() {
commonflags.Init(objectPutCmd) commonflags.Init(objectPutCmd)
commonflags.InitSession(objectPutCmd) initFlagSession(objectPutCmd, "PUT")
flags := objectPutCmd.Flags() flags := objectPutCmd.Flags()
@ -109,7 +108,7 @@ func putObject(cmd *cobra.Command, _ []string) {
} }
var prm internalclient.PutObjectPrm var prm internalclient.PutObjectPrm
sessionCli.Prepare(cmd, cnr, nil, pk, &prm) ReadOrOpenSession(cmd, &prm, pk, cnr, nil)
Prepare(cmd, &prm) Prepare(cmd, &prm)
prm.SetHeader(obj) prm.SetHeader(obj)

View file

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

View file

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

View file

@ -9,7 +9,9 @@ import (
internal "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client" 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/common"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "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/bearer"
"github.com/nspcc-dev/neofs-sdk-go/client"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id" cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa" neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id" 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.ExitOnErr(cmd, "decode object ID string: %w", err)
} }
// common interface of object operation's input which supports sessions. // SessionPrm is a common interface of object operation's input which supports
// Implemented on types like internal.PutObjectPrm. // sessions.
type sessionPrm interface { type SessionPrm interface {
SetSessionToken(*session.Object) SetSessionToken(*session.Object)
SetClient(*client.Client)
} }
// forwards all parameters to _readSession and object as nil. // forwards all parameters to _readVerifiedSession and object as nil.
func readSessionGlobal(cmd *cobra.Command, dst sessionPrm, key *ecdsa.PrivateKey, cnr cid.ID) { func readSessionGlobal(cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID) {
_readSession(cmd, dst, key, cnr, nil) _readVerifiedSession(cmd, dst, key, cnr, nil)
} }
// forwards all parameters to _readSession. // forwards all parameters to _readVerifiedSession.
func readSession(cmd *cobra.Command, dst sessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj oid.ID) { func readSession(cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj oid.ID) {
_readSession(cmd, dst, key, cnr, &obj) _readVerifiedSession(cmd, dst, key, cnr, &obj)
} }
// decodes object session from JSON file from "session" command flag if it is provided, // decodes session.Object from the file by path specified in the
// and writes resulting session into the provided sessionPrm. Checks: // 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 container
// - relation to the given object if non-nil // - relation to the given object if non-nil
// - relation to the given private key used within the command // - relation to the given private key used within the command
// - session signature // - session signature
// //
// sessionPrm MUST be one of: // SessionPrm MUST be one of:
// //
// *internal.PutObjectPrm
// *internal.DeleteObjectPrm
// *internal.GetObjectPrm // *internal.GetObjectPrm
// *internal.HeadObjectPrm // *internal.HeadObjectPrm
// *internal.SearchObjectsPrm // *internal.SearchObjectsPrm
// *internal.PayloadRangePrm // *internal.PayloadRangePrm
// *internal.HashPayloadRangesPrm // *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 var cmdVerb session.ObjectVerb
switch dst.(type) { switch dst.(type) {
default: default:
panic(fmt.Sprintf("unsupported op parameters %T", dst)) panic(fmt.Sprintf("unsupported op parameters %T", dst))
case *internal.PutObjectPrm:
cmdVerb = session.VerbObjectPut
case *internal.DeleteObjectPrm:
cmdVerb = session.VerbObjectDelete
case *internal.GetObjectPrm: case *internal.GetObjectPrm:
cmdVerb = session.VerbObjectGet cmdVerb = session.VerbObjectGet
case *internal.HeadObjectPrm: case *internal.HeadObjectPrm:
@ -143,32 +162,125 @@ func _readSession(cmd *cobra.Command, dst sessionPrm, key *ecdsa.PrivateKey, cnr
cmdVerb = session.VerbObjectRangeHash cmdVerb = session.VerbObjectRangeHash
} }
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken) tok := getSession(cmd)
if sessionTokenPath != "" { if tok == nil {
common.PrintVerbose("Reading object session from the JSON file [%s]...", sessionTokenPath) return
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.")
} }
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/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object" 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" cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id" oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -40,7 +39,7 @@ func delSG(cmd *cobra.Command, _ []string) {
addr := readObjectAddress(cmd, &cnr, &obj) addr := readObjectAddress(cmd, &cnr, &obj)
var prm internalclient.DeleteObjectPrm var prm internalclient.DeleteObjectPrm
sessionCli.Prepare(cmd, cnr, &obj, pk, &prm) objectCli.OpenSession(cmd, &prm, pk, cnr, &obj)
objectCli.Prepare(cmd, &prm) objectCli.Prepare(cmd, &prm)
prm.SetAddress(addr) 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/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object" 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" cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id" oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
storagegroupSDK "github.com/nspcc-dev/neofs-sdk-go/storagegroup" storagegroupSDK "github.com/nspcc-dev/neofs-sdk-go/storagegroup"
@ -46,9 +45,11 @@ func getSG(cmd *cobra.Command, _ []string) {
pk := key.GetOrGenerate(cmd) pk := key.GetOrGenerate(cmd)
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)
var prm internalclient.GetObjectPrm var prm internalclient.GetObjectPrm
sessionCli.Prepare(cmd, cnr, &obj, pk, &prm)
objectCli.Prepare(cmd, &prm) objectCli.Prepare(cmd, &prm)
prm.SetClient(cli)
raw, _ := cmd.Flags().GetBool(sgRawFlag) raw, _ := cmd.Flags().GetBool(sgRawFlag)
prm.SetRawFlag(raw) 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/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object" 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-node/pkg/services/object_manager/storagegroup"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id" cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -32,9 +31,11 @@ func listSG(cmd *cobra.Command, _ []string) {
pk := key.GetOrGenerate(cmd) pk := key.GetOrGenerate(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)
var prm internalclient.SearchObjectsPrm var prm internalclient.SearchObjectsPrm
sessionCli.Prepare(cmd, cnr, nil, pk, &prm)
objectCli.Prepare(cmd, &prm) objectCli.Prepare(cmd, &prm)
prm.SetClient(cli)
prm.SetContainerID(cnr) prm.SetContainerID(cnr)
prm.SetFilters(storagegroup.SearchQuery()) 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/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object" 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-node/pkg/services/object_manager/storagegroup"
"github.com/nspcc-dev/neofs-sdk-go/container" "github.com/nspcc-dev/neofs-sdk-go/container"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id" 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) resGetCnr, err := internalclient.GetContainer(getCnrPrm)
common.ExitOnErr(cmd, "get container RPC call: %w", err) 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) objectCli.Prepare(cmd, &headPrm, &putPrm)
headPrm.SetRawFlag(true) headPrm.SetRawFlag(true)
headPrm.SetClient(cli)
sg, err := storagegroup.CollectMembers(sgHeadReceiver{ sg, err := storagegroup.CollectMembers(sgHeadReceiver{
cmd: cmd, cmd: cmd,
@ -128,9 +128,6 @@ type sgHeadReceiver struct {
} }
func (c sgHeadReceiver) Head(addr oid.Address) (interface{}, error) { 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) c.prm.SetAddress(addr)
res, err := internalclient.HeadObject(c.prm) res, err := internalclient.HeadObject(c.prm)

View file

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