diff --git a/cmd/neofs-cli/modules/object.go b/cmd/neofs-cli/modules/object.go index ac5a49241..b4cc1445a 100644 --- a/cmd/neofs-cli/modules/object.go +++ b/cmd/neofs-cli/modules/object.go @@ -16,6 +16,7 @@ import ( "github.com/cheggaaa/pb" objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object" internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client" + 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" "github.com/nspcc-dev/neofs-sdk-go/object" @@ -316,30 +317,11 @@ func prepareSessionPrmWithOwner( ownerID *owner.ID, prms ...clientKeySession, ) { - var ( - sessionPrm internalclient.CreateSessionPrm - netInfoPrm internalclient.NetworkInfoPrm - ) + cli, err := getSDKClient(key) + exitOnErr(cmd, errf("create API client: %w", err)) - cws := make([]clientWithKey, 2, len(prms)+2) - cws[0] = &sessionPrm - cws[1] = &netInfoPrm - - for i := range prms { - cws = append(cws, prms[i]) - } - - prepareAPIClientWithKey(cmd, key, cws...) - - ni, err := internalclient.NetworkInfo(netInfoPrm) - exitOnErr(cmd, errf("read network info: %w", err)) - - cur := ni.NetworkInfo().CurrentEpoch() - exp := cur + sessionTokenLifetime - sessionPrm.SetExp(exp) - - sessionRes, err := internalclient.CreateSession(sessionPrm) - exitOnErr(cmd, errf("open session: %w", err)) + sessionToken, err := sessionCli.CreateSession(cli, ownerID, sessionTokenLifetime) + exitOnErr(cmd, err) for i := range prms { objectContext := session.NewObjectContext() @@ -364,17 +346,18 @@ func prepareSessionPrmWithOwner( objectContext.ApplyTo(addr) tok := session.NewToken() - tok.SetID(sessionRes.ID()) - tok.SetSessionKey(sessionRes.SessionKey()) - tok.SetOwnerID(ownerID) + tok.SetID(sessionToken.ID()) + tok.SetSessionKey(sessionToken.SessionKey()) + tok.SetOwnerID(sessionToken.OwnerID()) tok.SetContext(objectContext) - tok.SetExp(exp) - tok.SetIat(cur) - tok.SetNbf(cur) + tok.SetExp(sessionToken.Exp()) + tok.SetIat(sessionToken.Iat()) + tok.SetNbf(sessionToken.Nbf()) err = tok.Sign(key) exitOnErr(cmd, errf("session token signing: %w", err)) + prms[i].SetClient(cli) prms[i].SetSessionToken(tok) } } diff --git a/cmd/neofs-cli/modules/root.go b/cmd/neofs-cli/modules/root.go index fee32dcce..661bbd720 100644 --- a/cmd/neofs-cli/modules/root.go +++ b/cmd/neofs-cli/modules/root.go @@ -14,6 +14,7 @@ import ( "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/acl" bearerCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/bearer" + sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session" "github.com/nspcc-dev/neofs-node/misc" "github.com/nspcc-dev/neofs-node/pkg/network" "github.com/nspcc-dev/neofs-sdk-go/client" @@ -120,6 +121,7 @@ func init() { rootCmd.AddCommand(acl.Cmd) rootCmd.AddCommand(bearerCli.Cmd) + rootCmd.AddCommand(sessionCli.Cmd) } func entryPoint(cmd *cobra.Command, _ []string) { diff --git a/cmd/neofs-cli/modules/session/create.go b/cmd/neofs-cli/modules/session/create.go new file mode 100644 index 000000000..2e4d42028 --- /dev/null +++ b/cmd/neofs-cli/modules/session/create.go @@ -0,0 +1,127 @@ +package session + +import ( + "fmt" + "io/ioutil" + + internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client" + "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" + "github.com/nspcc-dev/neofs-node/pkg/network" + "github.com/nspcc-dev/neofs-sdk-go/client" + "github.com/nspcc-dev/neofs-sdk-go/owner" + "github.com/nspcc-dev/neofs-sdk-go/session" + "github.com/spf13/cobra" +) + +const ( + lifetimeFlag = "lifetime" + walletFlag = "wallet" + accountFlag = "address" + outFlag = "out" + jsonFlag = "json" + rpcFlag = "rpc-endpoint" +) + +const defaultLifetime = 10 + +var createCmd = &cobra.Command{ + Use: "create", + Short: "Create session token", + RunE: createSession, +} + +func init() { + createCmd.Flags().Uint64P(lifetimeFlag, "l", defaultLifetime, "number of epochs for token to stay valid") + createCmd.Flags().StringP(walletFlag, "w", "", "path to the wallet") + createCmd.Flags().StringP(accountFlag, "a", "", "account address") + createCmd.Flags().String(outFlag, "", "file to write session token to") + createCmd.Flags().Bool(jsonFlag, false, "output token in JSON") + createCmd.Flags().StringP(rpcFlag, "r", "", "rpc-endpoint") + + _ = cobra.MarkFlagRequired(createCmd.Flags(), lifetimeFlag) + _ = cobra.MarkFlagRequired(createCmd.Flags(), walletFlag) + _ = cobra.MarkFlagRequired(createCmd.Flags(), outFlag) + _ = cobra.MarkFlagRequired(createCmd.Flags(), rpcFlag) +} + +func createSession(cmd *cobra.Command, _ []string) error { + walletPath, _ := cmd.Flags().GetString(walletFlag) + accPath, _ := cmd.Flags().GetString(accountFlag) + privKey, err := key.Get(walletPath, accPath) + if err != nil { + return err + } + + var netAddr network.Address + addrStr, _ := cmd.Flags().GetString(rpcFlag) + if err := netAddr.FromString(addrStr); err != nil { + return err + } + + c, err := internalclient.GetSDKClient(privKey, netAddr) + if err != nil { + return err + } + + lifetime := uint64(defaultLifetime) + if lfArg, _ := cmd.Flags().GetUint64(lifetimeFlag); lfArg != 0 { + lifetime = lfArg + } + + ownerID := owner.NewIDFromPublicKey(&privKey.PublicKey) + tok, err := CreateSession(c, ownerID, lifetime) + if err != nil { + return err + } + + var data []byte + + if toJSON, _ := cmd.Flags().GetBool(jsonFlag); toJSON { + data, err = tok.MarshalJSON() + } else { + data, err = tok.Marshal() + } + if err != nil { + return fmt.Errorf("can't marshal token: %w", err) + } + + filename, _ := cmd.Flags().GetString(outFlag) + if err := ioutil.WriteFile(filename, data, 0644); err != nil { + return fmt.Errorf("can't write token to file: %w", err) + } + return nil +} + +// CreateSession returns newly created session token with the specified owner and lifetime. +// `Issued-At` and `Not-Valid-Before` fields are set to current epoch. +func CreateSession(c *client.Client, owner *owner.ID, lifetime uint64) (*session.Token, error) { + var netInfoPrm internalclient.NetworkInfoPrm + netInfoPrm.SetClient(c) + + ni, err := internalclient.NetworkInfo(netInfoPrm) + if err != nil { + return nil, fmt.Errorf("can't fetch network info: %w", err) + } + + cur := ni.NetworkInfo().CurrentEpoch() + exp := cur + lifetime + + var sessionPrm internalclient.CreateSessionPrm + sessionPrm.SetClient(c) + sessionPrm.SetExp(exp) + + sessionRes, err := internalclient.CreateSession(sessionPrm) + if err != nil { + return nil, fmt.Errorf("can't open session: %w", err) + } + + tok := session.NewToken() + tok.SetID(sessionRes.ID()) + tok.SetSessionKey(sessionRes.SessionKey()) + tok.SetOwnerID(owner) + tok.SetExp(exp) + tok.SetIat(cur) + tok.SetNbf(cur) + + return tok, nil +} diff --git a/cmd/neofs-cli/modules/session/root.go b/cmd/neofs-cli/modules/session/root.go new file mode 100644 index 000000000..3554a0ee1 --- /dev/null +++ b/cmd/neofs-cli/modules/session/root.go @@ -0,0 +1,14 @@ +package session + +import ( + "github.com/spf13/cobra" +) + +var Cmd = &cobra.Command{ + Use: "session", + Short: "Operations with session token", +} + +func init() { + Cmd.AddCommand(createCmd) +}