github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/cmd/list.go (about)

     1  /*
     2   * Copyright 2018-2020 The NATS Authors
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   * http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15  
    16  package cmd
    17  
    18  import (
    19  	"errors"
    20  	"fmt"
    21  	"sort"
    22  
    23  	cli "github.com/nats-io/cliprompts/v2"
    24  	"github.com/nats-io/jwt/v2"
    25  	"github.com/nats-io/nsc/v2/cmd/store"
    26  	"github.com/spf13/cobra"
    27  	"github.com/xlab/tablewriter"
    28  )
    29  
    30  // addCmd represents the add command
    31  var listCmd = &cobra.Command{
    32  	Use:   "list",
    33  	Short: "List assets such as accounts, imports, users",
    34  }
    35  
    36  func init() {
    37  	GetRootCmd().AddCommand(listCmd)
    38  	listCmd.AddCommand(createListOperatorsCmd())
    39  	listCmd.AddCommand(createListAccountsCmd())
    40  	listCmd.AddCommand(createListUsersCmd())
    41  }
    42  
    43  type EntryInfo struct {
    44  	Name   string
    45  	Claims jwt.Claims
    46  	Err    error
    47  }
    48  
    49  func createListOperatorsCmd() *cobra.Command {
    50  	cmd := &cobra.Command{
    51  		Use:   "operators",
    52  		Short: "List operators",
    53  		Args:  MaxArgs(0),
    54  		RunE: func(cmd *cobra.Command, args []string) error {
    55  			config := GetConfig()
    56  			if config.StoreRoot == "" {
    57  				return errors.New("no store set - `env --store <dir>`")
    58  			}
    59  			operators := config.ListOperators()
    60  			if len(operators) == 0 {
    61  				fmt.Printf("no operators defined in store dir %q\n"+
    62  					"init an environment or change the store root with `env --store <dir>`", config.StoreRoot)
    63  			} else {
    64  				sort.Strings(operators)
    65  				var infos []*EntryInfo
    66  				for _, v := range operators {
    67  					var i EntryInfo
    68  					infos = append(infos, &i)
    69  					i.Name = v
    70  					s, err := config.LoadStore(v)
    71  					if err != nil {
    72  						i.Err = err
    73  						continue
    74  					}
    75  					c, err := s.LoadRootClaim()
    76  					if err != nil {
    77  						i.Err = err
    78  						continue
    79  					}
    80  					if c == nil {
    81  						i.Err = fmt.Errorf("%q jwt not found", v)
    82  						continue
    83  					}
    84  					i.Claims = c
    85  				}
    86  				cmd.Println(listEntities("Operators", infos, config.Operator))
    87  			}
    88  
    89  			return nil
    90  		},
    91  	}
    92  	return cmd
    93  }
    94  
    95  func ListAccounts(s *store.Store) ([]*EntryInfo, error) {
    96  	accounts, err := s.ListSubContainers(store.Accounts)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	sort.Strings(accounts)
   101  
   102  	var infos []*EntryInfo
   103  	for _, v := range accounts {
   104  		var i EntryInfo
   105  		i.Name = v
   106  		infos = append(infos, &i)
   107  		ac, err := s.ReadAccountClaim(v)
   108  		if err != nil {
   109  			i.Err = err
   110  			continue
   111  		}
   112  		i.Claims = ac
   113  	}
   114  	return infos, nil
   115  }
   116  
   117  func createListAccountsCmd() *cobra.Command {
   118  	var operator string
   119  
   120  	cmd := &cobra.Command{
   121  		Use:   "accounts",
   122  		Short: "List accounts",
   123  		Args:  MaxArgs(0),
   124  		RunE: func(cmd *cobra.Command, args []string) error {
   125  			config := GetConfig()
   126  			if config.StoreRoot == "" {
   127  				return errors.New("no store set - `env --store <dir>`")
   128  			}
   129  			if operator != "" {
   130  				if err := config.SetOperator(operator); err != nil {
   131  					return err
   132  				}
   133  			}
   134  			if config.Operator == "" {
   135  				return errors.New("no operator set - `env --operator <name>`")
   136  			}
   137  			containers, err := config.ListAccounts()
   138  			if err != nil {
   139  				return err
   140  			}
   141  			sort.Strings(containers)
   142  			s, err := config.LoadStore(config.Operator)
   143  			if err != nil {
   144  				return err
   145  			}
   146  
   147  			var infos []*EntryInfo
   148  			for _, v := range containers {
   149  				var i EntryInfo
   150  				i.Name = v
   151  				infos = append(infos, &i)
   152  				ac, err := s.ReadAccountClaim(v)
   153  				if err != nil {
   154  					i.Err = err
   155  					continue
   156  				}
   157  				i.Claims = ac
   158  			}
   159  			cmd.Println(listEntities("Accounts", infos, config.Account))
   160  			return nil
   161  		},
   162  	}
   163  
   164  	cmd.Flags().StringVarP(&operator, "operator", "o", "", "operator name")
   165  
   166  	return cmd
   167  }
   168  
   169  func ListUsers(s *store.Store, accountName string) ([]*EntryInfo, error) {
   170  	names, err := s.ListEntries(store.Accounts, accountName, store.Users)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	sort.Strings(names)
   175  
   176  	var infos []*EntryInfo
   177  	for _, v := range names {
   178  		var i EntryInfo
   179  		i.Name = v
   180  		infos = append(infos, &i)
   181  		uc, err := s.ReadUserClaim(accountName, v)
   182  		if err != nil {
   183  			i.Err = err
   184  			continue
   185  		}
   186  		if uc == nil {
   187  			i.Err = fmt.Errorf("%q jwt not found", v)
   188  			continue
   189  		}
   190  		i.Claims = uc
   191  	}
   192  	return infos, nil
   193  }
   194  
   195  func createListUsersCmd() *cobra.Command {
   196  	var operator string
   197  	var account string
   198  	cmd := &cobra.Command{
   199  		Use:   "users",
   200  		Short: "List users",
   201  		Args:  MaxArgs(0),
   202  		RunE: func(cmd *cobra.Command, args []string) error {
   203  			config := GetConfig()
   204  			if config.StoreRoot == "" {
   205  				return fmt.Errorf("no store set - `%s env --store <dir>`", GetToolName())
   206  			}
   207  			if operator != "" {
   208  				if err := config.SetOperator(operator); err != nil {
   209  					return err
   210  				}
   211  			}
   212  			if config.Operator == "" {
   213  				return fmt.Errorf("no operator set - `%s env --operator <name>`", GetToolName())
   214  			}
   215  			if account != "" {
   216  				if err := config.SetAccount(account); err != nil {
   217  					return err
   218  				}
   219  			}
   220  			if config.Account == "" {
   221  				return fmt.Errorf("no account set - `%s env --account <name>`", GetToolName())
   222  			}
   223  
   224  			s, err := config.LoadStore(config.Operator)
   225  			if err != nil {
   226  				return err
   227  			}
   228  
   229  			infos, err := ListUsers(s, config.Account)
   230  			if err != nil {
   231  				return err
   232  			}
   233  
   234  			cmd.Println(listEntities("Users", infos, config.Account))
   235  			return nil
   236  		},
   237  	}
   238  
   239  	cmd.Flags().StringVarP(&operator, "operator", "o", "", "operator name")
   240  	cmd.Flags().StringVarP(&account, "account", "a", "", "account name")
   241  
   242  	return cmd
   243  }
   244  
   245  func listEntities(title string, infos []*EntryInfo, current string) string {
   246  	table := tablewriter.CreateTable()
   247  	table.AddTitle(title)
   248  	if len(infos) == 0 {
   249  		table.AddRow("No entries defined")
   250  	} else {
   251  		table.AddHeaders("Name", "Public Key")
   252  		for _, v := range infos {
   253  			n := v.Name
   254  			var p string
   255  			if v.Err != nil || v.Claims == nil {
   256  				p = fmt.Sprintf("error loading jwt - %v", v.Err)
   257  			} else {
   258  				c := v.Claims.Claims()
   259  				if c != nil {
   260  					tn := c.Name
   261  					if n != tn {
   262  						n = fmt.Sprintf("%s (%s)", n, c.Name)
   263  					}
   264  					p = c.Subject
   265  				}
   266  			}
   267  			if n == current {
   268  				n = cli.Bold(n)
   269  				p = cli.Bold(p)
   270  			}
   271  			table.AddRow(n, p)
   272  		}
   273  	}
   274  	return table.Render()
   275  }