github.com/crowdsecurity/crowdsec@v1.6.1/cmd/crowdsec-cli/items.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/csv"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"path/filepath"
    10  	"slices"
    11  	"strings"
    12  
    13  	"gopkg.in/yaml.v3"
    14  
    15  	"github.com/crowdsecurity/crowdsec/pkg/cwhub"
    16  )
    17  
    18  // selectItems returns a slice of items of a given type, selected by name and sorted by case-insensitive name
    19  func selectItems(hub *cwhub.Hub, itemType string, args []string, installedOnly bool) ([]*cwhub.Item, error) {
    20  	itemNames := hub.GetItemNames(itemType)
    21  
    22  	notExist := []string{}
    23  
    24  	if len(args) > 0 {
    25  		for _, arg := range args {
    26  			if !slices.Contains(itemNames, arg) {
    27  				notExist = append(notExist, arg)
    28  			}
    29  		}
    30  	}
    31  
    32  	if len(notExist) > 0 {
    33  		return nil, fmt.Errorf("item(s) '%s' not found in %s", strings.Join(notExist, ", "), itemType)
    34  	}
    35  
    36  	if len(args) > 0 {
    37  		itemNames = args
    38  		installedOnly = false
    39  	}
    40  
    41  	items := make([]*cwhub.Item, 0, len(itemNames))
    42  
    43  	for _, itemName := range itemNames {
    44  		item := hub.GetItem(itemType, itemName)
    45  		if installedOnly && !item.State.Installed {
    46  			continue
    47  		}
    48  
    49  		items = append(items, item)
    50  	}
    51  
    52  	cwhub.SortItemSlice(items)
    53  
    54  	return items, nil
    55  }
    56  
    57  func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item, omitIfEmpty bool) error {
    58  	switch csConfig.Cscli.Output {
    59  	case "human":
    60  		nothingToDisplay := true
    61  
    62  		for _, itemType := range itemTypes {
    63  			if omitIfEmpty && len(items[itemType]) == 0 {
    64  				continue
    65  			}
    66  
    67  			listHubItemTable(out, "\n"+strings.ToUpper(itemType), items[itemType])
    68  
    69  			nothingToDisplay = false
    70  		}
    71  
    72  		if nothingToDisplay {
    73  			fmt.Println("No items to display")
    74  		}
    75  	case "json":
    76  		type itemHubStatus struct {
    77  			Name         string `json:"name"`
    78  			LocalVersion string `json:"local_version"`
    79  			LocalPath    string `json:"local_path"`
    80  			Description  string `json:"description"`
    81  			UTF8Status   string `json:"utf8_status"`
    82  			Status       string `json:"status"`
    83  		}
    84  
    85  		hubStatus := make(map[string][]itemHubStatus)
    86  		for _, itemType := range itemTypes {
    87  			// empty slice in case there are no items of this type
    88  			hubStatus[itemType] = make([]itemHubStatus, len(items[itemType]))
    89  
    90  			for i, item := range items[itemType] {
    91  				status := item.State.Text()
    92  				statusEmo := item.State.Emoji()
    93  				hubStatus[itemType][i] = itemHubStatus{
    94  					Name:         item.Name,
    95  					LocalVersion: item.State.LocalVersion,
    96  					LocalPath:    item.State.LocalPath,
    97  					Description:  item.Description,
    98  					Status:       status,
    99  					UTF8Status:   fmt.Sprintf("%v  %s", statusEmo, status),
   100  				}
   101  			}
   102  		}
   103  
   104  		x, err := json.MarshalIndent(hubStatus, "", " ")
   105  		if err != nil {
   106  			return fmt.Errorf("failed to unmarshal: %w", err)
   107  		}
   108  
   109  		out.Write(x)
   110  	case "raw":
   111  		csvwriter := csv.NewWriter(out)
   112  
   113  		header := []string{"name", "status", "version", "description"}
   114  		if len(itemTypes) > 1 {
   115  			header = append(header, "type")
   116  		}
   117  
   118  		if err := csvwriter.Write(header); err != nil {
   119  			return fmt.Errorf("failed to write header: %s", err)
   120  		}
   121  
   122  		for _, itemType := range itemTypes {
   123  			for _, item := range items[itemType] {
   124  				row := []string{
   125  					item.Name,
   126  					item.State.Text(),
   127  					item.State.LocalVersion,
   128  					item.Description,
   129  				}
   130  				if len(itemTypes) > 1 {
   131  					row = append(row, itemType)
   132  				}
   133  
   134  				if err := csvwriter.Write(row); err != nil {
   135  					return fmt.Errorf("failed to write raw output: %s", err)
   136  				}
   137  			}
   138  		}
   139  
   140  		csvwriter.Flush()
   141  	}
   142  
   143  	return nil
   144  }
   145  
   146  func inspectItem(item *cwhub.Item, showMetrics bool) error {
   147  	switch csConfig.Cscli.Output {
   148  	case "human", "raw":
   149  		enc := yaml.NewEncoder(os.Stdout)
   150  		enc.SetIndent(2)
   151  
   152  		if err := enc.Encode(item); err != nil {
   153  			return fmt.Errorf("unable to encode item: %s", err)
   154  		}
   155  	case "json":
   156  		b, err := json.MarshalIndent(*item, "", "  ")
   157  		if err != nil {
   158  			return fmt.Errorf("unable to marshal item: %s", err)
   159  		}
   160  
   161  		fmt.Print(string(b))
   162  	}
   163  
   164  	if csConfig.Cscli.Output != "human" {
   165  		return nil
   166  	}
   167  
   168  	if item.State.Tainted {
   169  		fmt.Println()
   170  		fmt.Printf(`This item is tainted. Use "%s %s inspect --diff %s" to see why.`, filepath.Base(os.Args[0]), item.Type, item.Name)
   171  		fmt.Println()
   172  	}
   173  
   174  	if showMetrics {
   175  		fmt.Printf("\nCurrent metrics: \n")
   176  
   177  		if err := ShowMetrics(item); err != nil {
   178  			return err
   179  		}
   180  	}
   181  
   182  	return nil
   183  }