From 8bba490c3010891d4d47225f83847e09c07a26b4 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Thu, 20 Oct 2022 13:40:33 +0400 Subject: [PATCH] [#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 --- CHANGELOG.md | 1 + cmd/neofs-cli/internal/common/token.go | 45 ++-- cmd/neofs-cli/internal/commonflags/session.go | 13 +- cmd/neofs-cli/modules/container/create.go | 9 +- cmd/neofs-cli/modules/container/delete.go | 9 +- .../modules/container/list_objects.go | 8 +- cmd/neofs-cli/modules/container/root.go | 13 +- cmd/neofs-cli/modules/container/set_eacl.go | 9 +- cmd/neofs-cli/modules/container/util.go | 25 +++ cmd/neofs-cli/modules/object/delete.go | 5 +- cmd/neofs-cli/modules/object/get.go | 2 +- cmd/neofs-cli/modules/object/hash.go | 2 - cmd/neofs-cli/modules/object/head.go | 2 +- cmd/neofs-cli/modules/object/lock.go | 6 +- cmd/neofs-cli/modules/object/put.go | 5 +- cmd/neofs-cli/modules/object/range.go | 2 +- cmd/neofs-cli/modules/object/search.go | 2 +- cmd/neofs-cli/modules/object/util.go | 206 ++++++++++++++---- cmd/neofs-cli/modules/session/util.go | 75 ------- cmd/neofs-cli/modules/storagegroup/delete.go | 3 +- cmd/neofs-cli/modules/storagegroup/get.go | 5 +- cmd/neofs-cli/modules/storagegroup/list.go | 5 +- cmd/neofs-cli/modules/storagegroup/put.go | 7 +- cmd/neofs-cli/modules/util/sign_session.go | 6 +- 24 files changed, 259 insertions(+), 206 deletions(-) delete mode 100644 cmd/neofs-cli/modules/session/util.go diff --git a/CHANGELOG.md b/CHANGELOG.md index b9035b27..d5224ba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/cmd/neofs-cli/internal/common/token.go b/cmd/neofs-cli/internal/common/token.go index 1a58a551..3df7278e 100644 --- a/cmd/neofs-cli/internal/common/token.go +++ b/cmd/neofs-cli/internal/common/token.go @@ -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 diff --git a/cmd/neofs-cli/internal/commonflags/session.go b/cmd/neofs-cli/internal/commonflags/session.go index 559ddc47..72a9d922 100644 --- a/cmd/neofs-cli/internal/commonflags/session.go +++ b/cmd/neofs-cli/internal/commonflags/session.go @@ -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), ) } diff --git a/cmd/neofs-cli/modules/container/create.go b/cmd/neofs-cli/modules/container/create.go index c306f41b..5b25b38f 100644 --- a/cmd/neofs-cli/modules/container/create.go +++ b/cmd/neofs-cli/modules/container/create.go @@ -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 { diff --git a/cmd/neofs-cli/modules/container/delete.go b/cmd/neofs-cli/modules/container/delete.go index 05dc0def..53d7e83b 100644 --- a/cmd/neofs-cli/modules/container/delete.go +++ b/cmd/neofs-cli/modules/container/delete.go @@ -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) diff --git a/cmd/neofs-cli/modules/container/list_objects.go b/cmd/neofs-cli/modules/container/list_objects.go index 5b4da630..cfabfabc 100644 --- a/cmd/neofs-cli/modules/container/list_objects.go +++ b/cmd/neofs-cli/modules/container/list_objects.go @@ -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) } diff --git a/cmd/neofs-cli/modules/container/root.go b/cmd/neofs-cli/modules/container/root.go index 50b5a392..14225f36 100644 --- a/cmd/neofs-cli/modules/container/root.go +++ b/cmd/neofs-cli/modules/container/root.go @@ -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) } } diff --git a/cmd/neofs-cli/modules/container/set_eacl.go b/cmd/neofs-cli/modules/container/set_eacl.go index a54dcf6c..953d9804 100644 --- a/cmd/neofs-cli/modules/container/set_eacl.go +++ b/cmd/neofs-cli/modules/container/set_eacl.go @@ -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) diff --git a/cmd/neofs-cli/modules/container/util.go b/cmd/neofs-cli/modules/container/util.go index 517d1c4c..d9128c49 100644 --- a/cmd/neofs-cli/modules/container/util.go +++ b/cmd/neofs-cli/modules/container/util.go @@ -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 +} diff --git a/cmd/neofs-cli/modules/object/delete.go b/cmd/neofs-cli/modules/object/delete.go index a21c7d2e..82e2e713 100644 --- a/cmd/neofs-cli/modules/object/delete.go +++ b/cmd/neofs-cli/modules/object/delete.go @@ -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) diff --git a/cmd/neofs-cli/modules/object/get.go b/cmd/neofs-cli/modules/object/get.go index d163716e..2ed4b95b 100644 --- a/cmd/neofs-cli/modules/object/get.go +++ b/cmd/neofs-cli/modules/object/get.go @@ -25,7 +25,7 @@ var objectGetCmd = &cobra.Command{ func initObjectGetCmd() { commonflags.Init(objectGetCmd) - commonflags.InitSession(objectGetCmd) + initFlagSession(objectGetCmd, "GET") flags := objectGetCmd.Flags() diff --git a/cmd/neofs-cli/modules/object/hash.go b/cmd/neofs-cli/modules/object/hash.go index 7538dcfe..9ab76d3d 100644 --- a/cmd/neofs-cli/modules/object/hash.go +++ b/cmd/neofs-cli/modules/object/hash.go @@ -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) diff --git a/cmd/neofs-cli/modules/object/head.go b/cmd/neofs-cli/modules/object/head.go index da94bc52..5fce730f 100644 --- a/cmd/neofs-cli/modules/object/head.go +++ b/cmd/neofs-cli/modules/object/head.go @@ -27,7 +27,7 @@ var objectHeadCmd = &cobra.Command{ func initObjectHeadCmd() { commonflags.Init(objectHeadCmd) - commonflags.InitSession(objectHeadCmd) + initFlagSession(objectHeadCmd, "HEAD") flags := objectHeadCmd.Flags() diff --git a/cmd/neofs-cli/modules/object/lock.go b/cmd/neofs-cli/modules/object/lock.go index da50a7e4..2c76020d 100644 --- a/cmd/neofs-cli/modules/object/lock.go +++ b/cmd/neofs-cli/modules/object/lock.go @@ -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") diff --git a/cmd/neofs-cli/modules/object/put.go b/cmd/neofs-cli/modules/object/put.go index 4826015e..e8f57983 100644 --- a/cmd/neofs-cli/modules/object/put.go +++ b/cmd/neofs-cli/modules/object/put.go @@ -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) diff --git a/cmd/neofs-cli/modules/object/range.go b/cmd/neofs-cli/modules/object/range.go index 62fb2d85..3d5ecf8b 100644 --- a/cmd/neofs-cli/modules/object/range.go +++ b/cmd/neofs-cli/modules/object/range.go @@ -28,7 +28,7 @@ var objectRangeCmd = &cobra.Command{ func initObjectRangeCmd() { commonflags.Init(objectRangeCmd) - commonflags.InitSession(objectRangeCmd) + initFlagSession(objectRangeCmd, "RANGE") flags := objectRangeCmd.Flags() diff --git a/cmd/neofs-cli/modules/object/search.go b/cmd/neofs-cli/modules/object/search.go index 28dcbb76..681bacb6 100644 --- a/cmd/neofs-cli/modules/object/search.go +++ b/cmd/neofs-cli/modules/object/search.go @@ -30,7 +30,7 @@ var ( func initObjectSearchCmd() { commonflags.Init(objectSearchCmd) - commonflags.InitSession(objectSearchCmd) + initFlagSession(objectSearchCmd, "SEARCH") flags := objectSearchCmd.Flags() diff --git a/cmd/neofs-cli/modules/object/util.go b/cmd/neofs-cli/modules/object/util.go index 16b2d053..71ea61b2 100644 --- a/cmd/neofs-cli/modules/object/util.go +++ b/cmd/neofs-cli/modules/object/util.go @@ -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 " name. +func initFlagSession(cmd *cobra.Command, verb string) { + commonflags.InitSession(cmd, "object "+verb) } diff --git a/cmd/neofs-cli/modules/session/util.go b/cmd/neofs-cli/modules/session/util.go deleted file mode 100644 index 674b9061..00000000 --- a/cmd/neofs-cli/modules/session/util.go +++ /dev/null @@ -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) - } -} diff --git a/cmd/neofs-cli/modules/storagegroup/delete.go b/cmd/neofs-cli/modules/storagegroup/delete.go index 63e4576c..531fa17d 100644 --- a/cmd/neofs-cli/modules/storagegroup/delete.go +++ b/cmd/neofs-cli/modules/storagegroup/delete.go @@ -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) diff --git a/cmd/neofs-cli/modules/storagegroup/get.go b/cmd/neofs-cli/modules/storagegroup/get.go index a6ad85d5..238c82e0 100644 --- a/cmd/neofs-cli/modules/storagegroup/get.go +++ b/cmd/neofs-cli/modules/storagegroup/get.go @@ -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) diff --git a/cmd/neofs-cli/modules/storagegroup/list.go b/cmd/neofs-cli/modules/storagegroup/list.go index e24211dd..9be954ca 100644 --- a/cmd/neofs-cli/modules/storagegroup/list.go +++ b/cmd/neofs-cli/modules/storagegroup/list.go @@ -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()) diff --git a/cmd/neofs-cli/modules/storagegroup/put.go b/cmd/neofs-cli/modules/storagegroup/put.go index ef1ad4b8..d22c1bd5 100644 --- a/cmd/neofs-cli/modules/storagegroup/put.go +++ b/cmd/neofs-cli/modules/storagegroup/put.go @@ -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) diff --git a/cmd/neofs-cli/modules/util/sign_session.go b/cmd/neofs-cli/modules/util/sign_session.go index 1b4f1f7f..3ec169e1 100644 --- a/cmd/neofs-cli/modules/util/sign_session.go +++ b/cmd/neofs-cli/modules/util/sign_session.go @@ -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)