[#1261] neofs-cli: Allow to use relative epoch for bearer token

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2022-03-23 16:22:09 +03:00 committed by Alex Vanin
parent f2c1bc4bfb
commit cbe07120da

View file

@ -1,10 +1,19 @@
package token package token
import ( import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"strconv"
"time"
"github.com/nspcc-dev/neofs-node/pkg/network"
"github.com/nspcc-dev/neofs-sdk-go/client"
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl" eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/owner" "github.com/nspcc-dev/neofs-sdk-go/owner"
"github.com/nspcc-dev/neofs-sdk-go/token" "github.com/nspcc-dev/neofs-sdk-go/token"
@ -19,22 +28,30 @@ const (
ownerFlag = "owner" ownerFlag = "owner"
outFlag = "out" outFlag = "out"
jsonFlag = "json" jsonFlag = "json"
rpcFlag = "rpc-endpoint"
) )
var createCmd = &cobra.Command{ var createCmd = &cobra.Command{
Use: "create", Use: "create",
Short: "Create bearer token", Short: "Create bearer token",
RunE: createToken, Long: `Create bearer token.
All epoch flags can be specified relative to the current epoch with the +n syntax.
In this case --` + rpcFlag + ` flag should be specified and the epoch in bearer token
is set to current epoch + n.
`,
RunE: createToken,
} }
func init() { func init() {
createCmd.Flags().StringP(eaclFlag, "e", "", "path to the extended ACL table") createCmd.Flags().StringP(eaclFlag, "e", "", "path to the extended ACL table")
createCmd.Flags().Uint64P(issuedAtFlag, "i", 0, "epoch to issue token at") createCmd.Flags().StringP(issuedAtFlag, "i", "", "epoch to issue token at")
createCmd.Flags().Uint64P(notValidBeforeFlag, "n", 0, "not valid before epoch") createCmd.Flags().StringP(notValidBeforeFlag, "n", "", "not valid before epoch")
createCmd.Flags().Uint64P(expireAtFlag, "x", 0, "expiration epoch") createCmd.Flags().StringP(expireAtFlag, "x", "", "expiration epoch")
createCmd.Flags().StringP(ownerFlag, "o", "", "token owner") createCmd.Flags().StringP(ownerFlag, "o", "", "token owner")
createCmd.Flags().String(outFlag, "", "file to write token to") createCmd.Flags().String(outFlag, "", "file to write token to")
createCmd.Flags().Bool(jsonFlag, false, "output token in JSON") createCmd.Flags().Bool(jsonFlag, false, "output token in JSON")
createCmd.Flags().StringP(rpcFlag, "r", "", "rpc-endpoint")
_ = cobra.MarkFlagFilename(createCmd.Flags(), eaclFlag) _ = cobra.MarkFlagFilename(createCmd.Flags(), eaclFlag)
@ -46,9 +63,34 @@ func init() {
} }
func createToken(cmd *cobra.Command, _ []string) error { func createToken(cmd *cobra.Command, _ []string) error {
iat, _ := cmd.Flags().GetUint64(issuedAtFlag) iat, iatRelative, err := parseEpoch(cmd, issuedAtFlag)
exp, _ := cmd.Flags().GetUint64(expireAtFlag) if err != nil {
nvb, _ := cmd.Flags().GetUint64(notValidBeforeFlag) return err
}
exp, expRelative, err := parseEpoch(cmd, expireAtFlag)
if err != nil {
return err
}
nvb, nvbRelative, err := parseEpoch(cmd, notValidBeforeFlag)
if err != nil {
return err
}
if iatRelative || expRelative || nvbRelative {
endpoint, _ := cmd.Flags().GetString(rpcFlag)
currEpoch, err := getCurrentEpoch(endpoint)
if err != nil {
return err
}
if iatRelative {
iat += currEpoch
}
if expRelative {
exp += currEpoch
}
if nvbRelative {
nvb += currEpoch
}
}
if exp < nvb { if exp < nvb {
return fmt.Errorf("expiration epoch is less than not-valid-before epoch: %d < %d", exp, nvb) return fmt.Errorf("expiration epoch is less than not-valid-before epoch: %d < %d", exp, nvb)
} }
@ -77,7 +119,6 @@ func createToken(cmd *cobra.Command, _ []string) error {
} }
var data []byte var data []byte
var err error
toJSON, _ := cmd.Flags().GetBool(jsonFlag) toJSON, _ := cmd.Flags().GetBool(jsonFlag)
if toJSON { if toJSON {
@ -96,3 +137,65 @@ func createToken(cmd *cobra.Command, _ []string) error {
return nil return nil
} }
// parseEpoch parses epoch argument. Second return value is true if
// the specified epoch is relative, and false otherwise.
func parseEpoch(cmd *cobra.Command, flag string) (uint64, bool, error) {
s, _ := cmd.Flags().GetString(flag)
if len(s) == 0 {
return 0, false, nil
}
relative := s[0] == '+'
if relative {
s = s[1:]
}
epoch, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return 0, relative, fmt.Errorf("can't parse epoch for %s argument: %w", flag, err)
}
return epoch, relative, nil
}
// getCurrentEpoch returns current epoch.
func getCurrentEpoch(endpoint string) (uint64, error) {
var (
c client.Client
prmInit client.PrmInit
prmDial client.PrmDial
addr network.Address
)
if err := addr.FromString(endpoint); err != nil {
return 0, fmt.Errorf("can't parse RPC endpoint: %w", err)
}
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return 0, fmt.Errorf("can't generate key to sign query: %w", err)
}
prmInit.SetDefaultPrivateKey(*key)
prmInit.ResolveNeoFSFailures()
c.Init(prmInit)
prmDial.SetServerURI(addr.HostAddr())
if addr.TLSEnabled() {
prmDial.SetTLSConfig(&tls.Config{})
}
if err := c.Dial(prmDial); err != nil {
return 0, fmt.Errorf("can't initialize client: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
ni, err := c.NetworkInfo(ctx, client.PrmNetworkInfo{})
if err != nil {
return 0, err
}
return ni.Info().CurrentEpoch(), nil
}