frostfs-node/cmd/frostfs-cli/modules/session/create.go

136 lines
4.2 KiB
Go

package session
import (
"context"
"fmt"
"os"
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
"github.com/google/uuid"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const (
outFlag = "out"
jsonFlag = commonflags.JSON
)
const defaultLifetime = 10
var createCmd = &cobra.Command{
Use: "create",
Short: "Create session token",
Run: createSession,
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(commonflags.WalletPath, cmd.Flags().Lookup(commonflags.WalletPath))
_ = viper.BindPFlag(commonflags.Account, cmd.Flags().Lookup(commonflags.Account))
},
}
func init() {
createCmd.Flags().Uint64P(commonflags.Lifetime, "l", defaultLifetime, "Number of epochs for token to stay valid")
createCmd.Flags().StringP(commonflags.WalletPath, commonflags.WalletPathShorthand, commonflags.WalletPathDefault, commonflags.WalletPathUsage)
createCmd.Flags().StringP(commonflags.Account, commonflags.AccountShorthand, commonflags.AccountDefault, commonflags.AccountUsage)
createCmd.Flags().String(outFlag, "", "File to write session token to")
createCmd.Flags().Bool(jsonFlag, false, "Output token in JSON")
createCmd.Flags().StringP(commonflags.RPC, commonflags.RPCShorthand, commonflags.RPCDefault, commonflags.RPCUsage)
_ = cobra.MarkFlagRequired(createCmd.Flags(), commonflags.WalletPath)
_ = cobra.MarkFlagRequired(createCmd.Flags(), outFlag)
_ = cobra.MarkFlagRequired(createCmd.Flags(), commonflags.RPC)
}
func createSession(cmd *cobra.Command, _ []string) {
privKey := key.Get(cmd)
var netAddr network.Address
addrStr, _ := cmd.Flags().GetString(commonflags.RPC)
commonCmd.ExitOnErr(cmd, "can't parse endpoint: %w", netAddr.FromString(addrStr))
c, err := internalclient.GetSDKClient(cmd.Context(), cmd, privKey, netAddr)
commonCmd.ExitOnErr(cmd, "can't create client: %w", err)
lifetime := uint64(defaultLifetime)
if lfArg, _ := cmd.Flags().GetUint64(commonflags.Lifetime); lfArg != 0 {
lifetime = lfArg
}
var tok session.Object
err = CreateSession(cmd.Context(), &tok, c, lifetime)
commonCmd.ExitOnErr(cmd, "can't create session: %w", err)
var data []byte
if toJSON, _ := cmd.Flags().GetBool(jsonFlag); toJSON {
data, err = tok.MarshalJSON()
commonCmd.ExitOnErr(cmd, "can't decode session token JSON: %w", err)
} else {
data = tok.Marshal()
}
filename, _ := cmd.Flags().GetString(outFlag)
err = os.WriteFile(filename, data, 0o644)
commonCmd.ExitOnErr(cmd, "can't write token to file: %w", err)
}
// CreateSession opens a new communication with FrostFS storage node using client connection.
// The session is expected to be maintained by the storage node during the given
// number of epochs.
//
// Fills ID, lifetime and session key.
func CreateSession(ctx context.Context, dst *session.Object, c *client.Client, lifetime uint64) error {
netInfoPrm := internalclient.NetworkInfoPrm{
Client: c,
}
ni, err := internalclient.NetworkInfo(ctx, netInfoPrm)
if err != nil {
return fmt.Errorf("can't fetch network info: %w", err)
}
cur := ni.NetworkInfo().CurrentEpoch()
exp := cur + lifetime
var sessionPrm internalclient.CreateSessionPrm
sessionPrm.SetClient(c)
sessionPrm.Expiration = exp
sessionRes, err := internalclient.CreateSession(ctx, sessionPrm)
if err != nil {
return fmt.Errorf("can't open session: %w", err)
}
binIDSession := sessionRes.ID()
var keySession frostfsecdsa.PublicKey
err = keySession.Decode(sessionRes.SessionKey())
if err != nil {
return fmt.Errorf("decode public session key: %w", err)
}
var idSession uuid.UUID
err = idSession.UnmarshalBinary(binIDSession)
if err != nil {
return fmt.Errorf("decode session ID: %w", err)
}
dst.SetID(idSession)
dst.SetNbf(cur)
dst.SetIat(cur)
dst.SetExp(exp)
dst.SetAuthKey(&keySession)
return nil
}