Skip to content

Commit

Permalink
Refactor describe commands into common base command removing duplicat…
Browse files Browse the repository at this point in the history
…ed logic and simplifying error handling

Signed-off-by: Alberto Ricart <[email protected]>
  • Loading branch information
aricart committed Jan 5, 2025
1 parent a28601d commit 2ff65c4
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 334 deletions.
81 changes: 59 additions & 22 deletions cmd/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@ import (
"fmt"

"github.com/nats-io/jwt/v2"
"github.com/nats-io/nsc/v2/cmd/store"
"github.com/spf13/cobra"
)

var Raw bool
var WideFlag bool
var Wide = noopNameFilter
var Json bool
var JsonPath string
var (
Raw bool
WideFlag bool
Wide = noopNameFilter
Json bool
JsonPath string
)

type WideFun = func(a string) string

Expand Down Expand Up @@ -106,67 +109,101 @@ func bodyAsJson(data []byte) ([]byte, error) {
return j.Bytes(), nil
}

type Describe struct {
raw []byte
kind jwt.ClaimType
type BaseDescribe struct {
raw []byte
kind jwt.ClaimType
outputFile string
}

func NewDescribe(raw []byte) (*Describe, error) {
token, err := jwt.ParseDecoratedJWT(raw)
func (p *BaseDescribe) Init() error {
token, err := jwt.ParseDecoratedJWT(p.raw)
if err != nil {
return nil, err
return err
}
p.raw = []byte(token)
gc, err := jwt.DecodeGeneric(token)
if err != nil {
return err
}
p.kind = gc.ClaimType()
return nil
}

func (p *BaseDescribe) Describe(ctx ActionCtx) (store.Status, error) {
var out []byte
var err error

if Raw {
out, err = p.Raw(!IsStdOut(p.outputFile))
} else if Json || JsonPath != "" {
out, err = p.JSON(JsonPath)
} else {
out, err = p.Structured()
}
if err != nil {
return nil, err
}
kind := gc.ClaimType()
return &Describe{raw: raw, kind: kind}, nil
if IsStdOut(p.outputFile) {
_, err = fmt.Fprintln(ctx.CurrentCmd().OutOrStdout(), string(out))
} else {
err = WriteFile(p.outputFile, out)
}
if err != nil {
return nil, err
}
if !IsStdOut(p.outputFile) {
k := "description"
if Raw {
k = "jwt"
}
return store.OKStatus("wrote %s %s to %#q", string(p.kind), k, AbbrevHomePaths(p.outputFile)), nil
}
return nil, err
}

func (p *Describe) Structured() (string, error) {
func (p *BaseDescribe) Structured() ([]byte, error) {
var describer Describer
switch p.kind {
case jwt.AccountClaim:
ac, err := jwt.DecodeAccountClaims(string(p.raw))
if err != nil {
return "", err
return []byte(""), err
}
describer = NewAccountDescriber(*ac)
case jwt.ActivationClaim:
ac, err := jwt.DecodeActivationClaims(string(p.raw))
if err != nil {
return "", err
return []byte(""), err
}
describer = NewActivationDescriber(*ac)
case jwt.UserClaim:
uc, err := jwt.DecodeUserClaims(string(p.raw))
if err != nil {
return "", err
return []byte(""), err
}
describer = NewUserDescriber(*uc)
case jwt.OperatorClaim:
oc, err := jwt.DecodeOperatorClaims(string(p.raw))
if err != nil {
return "", err
return []byte(""), err
}
describer = NewOperatorDescriber(*oc)
}

if describer == nil {
return "", fmt.Errorf("describer for %q is not implemented", p.kind)
return []byte(""), fmt.Errorf("describer for %q is not implemented", p.kind)
}
return describer.Describe(), nil
return []byte(describer.Describe()), nil
}

func (p *Describe) Raw(decorate bool) ([]byte, error) {
func (p *BaseDescribe) Raw(decorate bool) ([]byte, error) {
if decorate {
return jwt.DecorateJWT(string(p.raw))
}
return p.raw, nil
}

func (p *Describe) JSON(jsonPath string) ([]byte, error) {
func (p *BaseDescribe) JSON(jsonPath string) ([]byte, error) {
raw, err := bodyAsJson(p.raw)
if err != nil {
return nil, err
Expand Down
63 changes: 8 additions & 55 deletions cmd/describeaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
package cmd

import (
"fmt"
"github.com/nats-io/jwt/v2"
"github.com/nats-io/nsc/v2/cmd/store"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -45,8 +43,7 @@ func init() {

type DescribeAccountParams struct {
AccountContextParams
outputFile string
raw []byte
BaseDescribe
}

func (p *DescribeAccountParams) SetDefaults(ctx ActionCtx) error {
Expand All @@ -60,68 +57,24 @@ func (p *DescribeAccountParams) PreInteractive(ctx ActionCtx) error {

func (p *DescribeAccountParams) Load(ctx ActionCtx) error {
var err error

if err = p.AccountContextParams.Validate(ctx); err != nil {
return err
}
if Json || Raw || JsonPath != "" {
// load the JWT
p.raw, err = ctx.StoreCtx().Store.ReadRawAccountClaim(p.AccountContextParams.Name)
if err != nil {
return err
}
if Raw {
// if outputting to a file, decorate
if !IsStdOut(p.outputFile) {
p.raw, err = jwt.DecorateJWT(string(p.raw))
}
} else {
// JSON output
p.raw, err = bodyAsJson(p.raw)
if err != nil {
return err
}
if JsonPath != "" {
p.raw, err = GetField(p.raw, JsonPath)
if err != nil {
return err
}
}
}
} else {
// describe
ac, err := ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
if err != nil {
return err
}
v := NewAccountDescriber(*ac).Describe()
p.raw = []byte(v)
p.raw, err = ctx.StoreCtx().Store.ReadRawAccountClaim(p.AccountContextParams.Name)
if err != nil {
return err
}
return nil
return p.Init()
}

func (p *DescribeAccountParams) Validate(_ ActionCtx) error {
return nil
func (p *DescribeAccountParams) Validate(ctx ActionCtx) error {
return p.AccountContextParams.Validate(ctx)
}

func (p *DescribeAccountParams) PostInteractive(_ ActionCtx) error {
return nil
}

func (p *DescribeAccountParams) Run(ctx ActionCtx) (store.Status, error) {
var err error
if IsStdOut(p.outputFile) {
_, err = fmt.Fprintln(ctx.CurrentCmd().OutOrStdout(), string(p.raw))
return nil, nil
} else {
err = WriteFile(p.outputFile, p.raw)
if err != nil {
return nil, err
}
k := "description"
if Raw {
k = "jwt"
}
return store.OKStatus("wrote account %s to %#q", k, AbbrevHomePaths(p.outputFile)), nil
}
return p.Describe(ctx)
}
104 changes: 11 additions & 93 deletions cmd/describejwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ package cmd
import (
"errors"
"fmt"
"github.com/nats-io/nsc/v2/cmd/store"

cli "github.com/nats-io/cliprompts/v2"
"github.com/nats-io/jwt/v2"
"github.com/nats-io/nsc/v2/cmd/store"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -51,10 +50,8 @@ func init() {
}

type DescribeFile struct {
file string
kind jwt.ClaimType
outputFile string
token string
file string
BaseDescribe
}

func (p *DescribeFile) SetDefaults(ctx ActionCtx) error {
Expand All @@ -68,106 +65,27 @@ func (p *DescribeFile) PreInteractive(ctx ActionCtx) error {
}

func (p *DescribeFile) Load(ctx ActionCtx) error {
var err error
if p.file == "" {
ctx.CurrentCmd().SilenceErrors = false
ctx.CurrentCmd().SilenceUsage = false
return errors.New("file is required")
}
if d, err := LoadFromFileOrURL(p.file); err == nil {
p.token, err = jwt.ParseDecoratedJWT(d)
if err != nil {
return err
}
gc, err := jwt.DecodeGeneric(p.token)
if err != nil {
return err
}
p.kind = gc.ClaimType()
p.raw, err = LoadFromFileOrURL(p.file)
if err != nil {
return err
}
return nil
return p.Init()
}

func (p *DescribeFile) PostInteractive(ctx ActionCtx) error {
func (p *DescribeFile) Validate(_ ActionCtx) error {
return nil
}

func (p *DescribeFile) Validate(ctx ActionCtx) error {
func (p *DescribeFile) PostInteractive(_ ActionCtx) error {
return nil
}

func (p *DescribeFile) handleRaw() (store.Status, error) {
var err error
var raw []byte
if Json || JsonPath != "" {
raw, err = bodyAsJson([]byte(p.token))
if err != nil {
return nil, err
}
if JsonPath != "" {
raw, err = GetField(raw, JsonPath)
if err != nil {
return nil, err
}
}
}
raw = append(raw, '\n')
if err := Write(p.outputFile, raw); err != nil {
return nil, err
}
var s store.Status
if !IsStdOut(p.outputFile) {
k := "description"
if Raw {
k = "jwt"
}
s = store.OKStatus("wrote jwt %s to %#q", k, AbbrevHomePaths(p.outputFile))
}
return s, nil
}

func (p *DescribeFile) Run(ctx ActionCtx) (store.Status, error) {
if Json || Raw || JsonPath != "" {
return p.handleRaw()
}

var describer Describer
switch p.kind {
case jwt.AccountClaim:
ac, err := jwt.DecodeAccountClaims(p.token)
if err != nil {
return nil, err
}
describer = NewAccountDescriber(*ac)
case jwt.ActivationClaim:
ac, err := jwt.DecodeActivationClaims(p.token)
if err != nil {
return nil, err
}
describer = NewActivationDescriber(*ac)
case jwt.UserClaim:
uc, err := jwt.DecodeUserClaims(p.token)
if err != nil {
return nil, err
}
describer = NewUserDescriber(*uc)
case jwt.OperatorClaim:
oc, err := jwt.DecodeOperatorClaims(p.token)
if err != nil {
return nil, err
}
describer = NewOperatorDescriber(*oc)
}

if describer == nil {
return nil, fmt.Errorf("describer for %q is not implemented", p.kind)
}

if err := Write(p.outputFile, []byte(describer.Describe())); err != nil {
return nil, err
}
var s store.Status
if !IsStdOut(p.outputFile) {
s = store.OKStatus("wrote account description to %#q", AbbrevHomePaths(p.outputFile))
}
return s, nil
return p.Describe(ctx)
}
Loading

0 comments on commit 2ff65c4

Please sign in to comment.